/* * Copyright 2016 higherfrequencytrading.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.openhft.performance.tests.network; import net.openhft.chronicle.bytes.Bytes; import net.openhft.chronicle.core.threads.EventLoop; import net.openhft.chronicle.core.threads.HandlerPriority; import net.openhft.chronicle.core.threads.ThreadDump; import net.openhft.chronicle.network.AcceptorEventHandler; import net.openhft.chronicle.network.TCPRegistry; import net.openhft.chronicle.network.VanillaNetworkContext; import net.openhft.chronicle.network.connection.FatalFailureConnectionStrategy; import net.openhft.chronicle.network.connection.TcpChannelHub; import net.openhft.chronicle.network.connection.TryLock; import net.openhft.chronicle.threads.EventGroup; import net.openhft.chronicle.wire.TextWire; import net.openhft.chronicle.wire.Wire; import net.openhft.chronicle.wire.WireType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.nio.channels.ServerSocketChannel; import java.util.concurrent.TimeoutException; import static net.openhft.chronicle.network.connection.SocketAddressSupplier.uri; /** * Created by rob on 26/08/2015. */ public class SimpleServerAndClientTest { private ThreadDump threadDump; private static final Logger LOG = LoggerFactory.getLogger(SimpleServerAndClientTest.class); @Before public void threadDump() { threadDump = new ThreadDump(); } @After public void checkThreadDump() { threadDump.assertNoNewThreads(); } @Test public void test() throws IOException, TimeoutException, InterruptedException { //YamlLogging.setAll(true); for (; ; ) { // this the name of a reference to the host name and port, // allocated automatically when to a free port on localhost @NotNull final String desc = "host.port"; TCPRegistry.createServerSocketChannelFor(desc); // we use an event loop rather than lots of threads try (@NotNull EventLoop eg = new EventGroup(true)) { eg.start(); // an example message that we are going to send from the server to the client and back @NotNull final String expectedMessage = "<my message>"; createServer(desc, eg); try (@NotNull TcpChannelHub tcpChannelHub = createClient(eg, desc)) { // create the message the client sends to the server // the tid must be unique, its reflected back by the server, it must be at the start // of each message sent from the server to the client. Its use by the client to identify which // thread will handle this message final long tid = tcpChannelHub.nextUniqueTransaction(System.currentTimeMillis()); // we will use a text wire backed by a elasticByteBuffer @NotNull final Wire wire = new TextWire(Bytes.elasticByteBuffer()); wire.writeDocument(true, w -> w.write(() -> "tid").int64(tid)); wire.writeDocument(false, w -> w.write(() -> "payload").text(expectedMessage)); // write the data to the socket tcpChannelHub.lock2(() -> tcpChannelHub.writeSocket(wire, true), true, TryLock.TRY_LOCK_WARN); // read the reply from the socket ( timeout after 5 second ), note: we have to pass // the tid try { Wire reply = tcpChannelHub.proxyReply(5000, tid); // read the reply and check the result reply.readDocument(null, data -> { @Nullable final String text = data.read(() -> "payloadResponse").text(); Assert.assertEquals(expectedMessage, text); }); } catch (TimeoutException e) { // retry, you will get this is the client attempts to send a message to // the server and the server is not running or ready // note : that net.openhft.chronicle.network.TCPRegistry // .createServerSocketChannelFor() // opens a server socket, that does not mean that there is a server // running to read this, for example if you commented out "createServer(desc, eg); " // and this time out exception will be thrown continue; } break; } } finally { TcpChannelHub.closeAllHubs(); TCPRegistry.reset(); } } } @NotNull private TcpChannelHub createClient(@NotNull EventLoop eg, String desc) { return new TcpChannelHub(null, eg, WireType.TEXT, "/", uri(desc), false, null, HandlerPriority.TIMER, new FatalFailureConnectionStrategy(3)); } private void createServer(@NotNull String desc, @NotNull EventLoop eg) throws IOException { @NotNull AcceptorEventHandler eah = new AcceptorEventHandler(desc, LegacyHanderFactory.simpleTcpEventHandlerFactory(WireEchoRequestHandler::new, WireType.TEXT), VanillaNetworkContext::new); eg.addHandler(eah); ServerSocketChannel sc = TCPRegistry.acquireServerSocketChannel(desc); sc.configureBlocking(false); } }