@Test public void testEcho() throws Exception { Socket client = newClient(); client.setSoTimeout(60000); SocketChannel server = _connector.accept(); server.configureBlocking(false); _manager.accept(server); // Write client to server client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8)); // Verify echo server to client for (char c : "HelloWorld".toCharArray()) { int b = client.getInputStream().read(); assertTrue(b > 0); assertEquals(c, (char) b); } // wait for read timeout client.setSoTimeout(500); long start = System.currentTimeMillis(); try { client.getInputStream().read(); Assert.fail(); } catch (SocketTimeoutException e) { long duration = System.currentTimeMillis() - start; Assert.assertThat("timeout duration", duration, greaterThanOrEqualTo(400L)); } // write then shutdown client.getOutputStream().write("Goodbye Cruel TLS".getBytes(StandardCharsets.UTF_8)); // Verify echo server to client for (char c : "Goodbye Cruel TLS".toCharArray()) { int b = client.getInputStream().read(); Assert.assertThat("expect valid char integer", b, greaterThan(0)); assertEquals("expect characters to be same", c, (char) b); } client.close(); for (int i = 0; i < 10; ++i) { if (server.isOpen()) Thread.sleep(10); else break; } assertFalse(server.isOpen()); }
@Test public void testWriteBlocked() throws Exception { Socket client = newClient(); client.setSoTimeout(10000); SocketChannel server = _connector.accept(); server.configureBlocking(false); _manager.accept(server); // Write client to server _writeCount = 10000; String data = "Now is the time for all good men to come to the aid of the party"; client.getOutputStream().write(data.getBytes(StandardCharsets.UTF_8)); BufferedInputStream in = new BufferedInputStream(client.getInputStream()); int byteNum = 0; try { for (int i = 0; i < _writeCount; i++) { if (i % 1000 == 0) TimeUnit.MILLISECONDS.sleep(200); // Verify echo server to client for (int j = 0; j < data.length(); j++) { char c = data.charAt(j); int b = in.read(); byteNum++; assertTrue(b > 0); assertEquals("test-" + i + "/" + j, c, (char) b); } if (i == 0) _lastEndPoint.setIdleTimeout(60000); } } catch (SocketTimeoutException e) { System.err.println("SelectorManager.dump() = " + _manager.dump()); LOG.warn("Server: " + server); LOG.warn("Error reading byte #" + byteNum, e); throw e; } client.close(); for (int i = 0; i < 10; ++i) { if (server.isOpen()) Thread.sleep(10); else break; } assertFalse(server.isOpen()); }
/** * Sends a packet of data to the client through {@code buffer}. * * @param buffer the packet of data to send. */ public void send(ByteBuffer buffer) { if (!channel.isOpen() || packetDisconnect || combatLogout) return; buffer.flip(); try { channel.write(buffer); } catch (Exception ex) { ex.printStackTrace(); disconnect(true); } }
private synchronized void close() throws IOException { data = null; dataLengthBuffer = null; if (!channel.isOpen()) return; try { socket.shutdownOutput(); } catch (Exception e) { } if (channel.isOpen()) { try { channel.close(); } catch (Exception e) { } } try { socket.close(); } catch (Exception e) { } }
public void disconnect() { if (isConnected()) { try { inputStream.close(); outputStream.close(); if (channel.isOpen()) { channel.close(); } } catch (IOException ex) { throw new JedisConnectionException(ex); } } }
private Command readAsciiCommand() throws IOException { SocketChannel channel = this.socket.getChannel(); if (channel == null || !channel.isOpen()) { throw new IllegalStateException("cannot read from channel"); } buffer.clear(); int bytesRead = channel.read(buffer); if (bytesRead == -1) { throw new IOException("EOF"); } buffer.flip(); return Command.valueOf(readCommand(buffer)); }
@Override public void run() { try { while (!mStopSignal) { final SocketChannel lSocketChannel = mServerSocketChannel.accept(); // System.out.println("connection accepted"); lSocketChannel.setOption( StandardSocketOptions.SO_SNDBUF, ClearVolumeTCPClient.cSocketBufferLength); try { if (lSocketChannel.isOpen() && lSocketChannel.isConnected() && mClearVolumeTCPServerSink.getLastVolumeSeen() != null) { // System.out.println("sending last seen volume: " + // mClearVolumeTCPServerSink.getLastVolumeSeen()); sendVolumeToClient( lSocketChannel, mClearVolumeTCPServerSink.getLastVolumeSeen(), false); } while (lSocketChannel.isOpen() && lSocketChannel.isConnected() && !mStopSignal) { final Volume lVolumeToSend = mVolumeSource.requestVolumeAndWait(10, TimeUnit.MILLISECONDS); if (lVolumeToSend != null) sendVolumeToClient(lSocketChannel, lVolumeToSend, true); } } catch (final java.io.IOException e1) { continue; } catch (final Throwable e) { e.printStackTrace(); } } } catch (final java.nio.channels.AsynchronousCloseException e) { } catch (final Throwable e) { handleError(e); } finally { mStoppedSignal = true; } }
public void sendException(Exception e) { SocketChannel channel = this.socket.getChannel(); if (channel == null || !channel.isOpen()) { throw new IllegalStateException("cannot write to channel"); } try { if (e instanceof ClientError) { channel.write(charsetASCII.encode(Reply.CLIENT_ERROR.toString())); } else { channel.write(charsetASCII.encode(Reply.ERROR.toString())); } } catch (IOException ex) { } }
private void readText(Connection c) throws IOException { sc = c.channel(); buffer.clear(); if (sc == null || c.isWriteDisabled() || !sc.isOpen()) { c.close(false); } try { synchronized (sc) { read = sc.read(buffer); } } catch (IOException e) { if (debugEnabled) log.debug("IOException reading from connection " + c, e); c.close(false); } if (read > 0) { buffer.flip(); if (debugEnabled) log.debug("Connection " + c + " about to process data from buffer " + buffer); if (workersEnabled) { try { choose().add(c, buffer); } catch (RuntimeException e) { if (debugEnabled) log.debug("Cannot queue packet " + buffer + " for connection " + c, e); c.close(false); } } else { try { if (!c.processData(buffer)) { c.close(false); return; } } catch (Exception e) { log.error( e.getClass().getSimpleName() + " while processing buffer " + buffer + " for connection " + c, e); } } } else if (read < 0) { c.close(false); } }
private void sendVolumeToClient( SocketChannel lSocketChannel, Volume lVolumeToSend, boolean pReleaseOrForward) throws IOException { mByteBuffer = ClearVolumeSerialization.serialize(lVolumeToSend, mByteBuffer); mByteBuffer.rewind(); if (lSocketChannel.isConnected() && lSocketChannel.isOpen()) { while (mByteBuffer.hasRemaining()) lSocketChannel.write(mByteBuffer); if (pReleaseOrForward) { if (mClearVolumeTCPServerSink.getRelaySink() == null) lVolumeToSend.makeAvailableToManager(); else mClearVolumeTCPServerSink.getRelaySink().sendVolume(lVolumeToSend); } } }
/** * Creates a NonBlockingConnection wrapping channel. If the channel is not yet connected, * writeAvailable() must be called when it is connected. * * @param channel SocketChannel used for I/O. Must be open. */ public NonBlockingConnection(SocketChannel channel) { this(channel, channel); try { // NOTE: On Mac OS X, when an async connect to a localhost socket fails, this // can fail with an illegal argument exception, before finishConnect() is called. channel.socket().setTcpNoDelay(true); channel.configureBlocking(false); } catch (IOException e) { throw new RuntimeException(e); } if (!channel.isConnected()) { if (!channel.isOpen()) { // not possible? configureBlocking will throw ClosedChannelException throw new IllegalArgumentException("channel is closed"); } // The channel ether has a pending connect, or the connect hasn't started. writeBlocked = true; } else { // We haven't started connecting yet, to avoid the setTcpNoDelay issue assert channel.isConnectionPending() || channel.isOpen(); } }
public void start() throws IOException { System.err.println("Start"); SocketChannel control = SocketChannel.open(new InetSocketAddress("localhost", 8080)); control.write(BufferUtil.toBuffer(start)); while (control.isOpen()) { BufferUtil.clear(responseBuf); int pos = BufferUtil.flipToFill(responseBuf); if (control.read(responseBuf) == -1) control.close(); BufferUtil.flipToFlush(responseBuf, pos); } client = new SocketChannel[8]; for (int i = 0; i < client.length; i++) client[i] = SocketChannel.open(new InetSocketAddress("localhost", 8080)); }
public void sendMessage(final M msg) throws CatException { if (isClosed()) { throw new ConnectionException("Connection is not ready to send message:\n" + msg); } try { socketChannel.write(ByteBuffer.wrap(msg.toString().getBytes())); } catch (final IOException e) { if (socketChannel.isOpen()) { e.printStackTrace(); } else { // assume that the connection is proactively closed. } throw new ConnectionException("IOException occurred while sending message:\n" + msg); } }
public void sendReply(ByteBuffer reply) throws IOException { // for binary set the response opCode if (this.protocol == Protocol.BINARY) { reply.rewind(); reply.put(POSITION_OPCODE, buffer.get(POSITION_OPCODE)); reply.putInt(POSITION_OPAQUE, buffer.getInt(POSITION_OPAQUE)); if (ConnectionHandler.getLogger().finerEnabled()) { ConnectionHandler.getLogger() .finer("sending reply:" + reply + " " + Command.buffertoString(reply)); } } SocketChannel channel = this.socket.getChannel(); if (channel == null || !channel.isOpen()) { throw new IllegalStateException("cannot write to channel"); } channel.write(reply); }
@Override public void run() { log.debug("network thread started"); try { // run once InetSocketAddress address = new InetSocketAddress(host, port); channel = SocketChannel.open(address); channel.configureBlocking(true); reportChannel(); // main loop while (!Thread.currentThread().isInterrupted()) { int bytesRead = channel.read(readBuffer); if (bytesRead == -1) break; // TODO these StringBuilder shenanigans are fake // actually put chars in a CharBuffer and write to parser // parser returns list of events to be dispatched readBuffer.flip(); while (readBuffer.hasRemaining()) { sb.append((char) (readBuffer.get() & 0xFF)); } dispatchEvent(EventType.TEXT_RECEIVED, null, sb.toString()); sb.setLength(0); readBuffer.clear(); } } catch (ClosedByInterruptException e) { // normal result of being interrupted } catch (Throwable t) { log.error("network error", t); dispatchEvent(EventType.NETWORK_ERROR, null, t); } finally { if (channel != null && channel.isOpen()) { try { channel.close(); } catch (IOException e) { // ignore } } reportStatus(NetworkState.DISCONNECTED); log.debug("network thread exiting"); } }
@Override public void process(SocietyPacket inPacket, SocketChannel conn) { int sendBufferSize; byte[] sendData; ByteBuffer sendBuffer; ArrayList<SocketChannel> subscribers; subscribers = shared.subscribers.getSubscribers(inPacket.source); if (subscribers != null) { try { sendData = inPacket.serialize(); sendBuffer = ByteBuffer.wrap(sendData); for (SocketChannel sub : subscribers) { if (sub.isOpen()) { sendBuffer.clear(); sendBufferSize = sub.socket().getSendBufferSize(); if (sendBuffer.capacity() > sendBufferSize) { sendBuffer.limit(sendBufferSize); } while (sendBuffer.position() != sendBuffer.capacity()) { // could send less bytes than buffer size sub.write(sendBuffer); if ((sendBuffer.limit() + sendBufferSize) <= sendBuffer.capacity()) { sendBuffer.limit(sendBuffer.limit() + sendBufferSize); } else { sendBuffer.limit(sendBuffer.capacity()); } } } else { shared.subscribers.removeSubscriber(sub); } } } catch (IOException e) { e.printStackTrace(); } } else { System.out.println("no subscribers"); } inPacket = null; }
/** * This will only close the connection without taking care of the rest. May be called only by * Dispatcher Thread. Returns true if connection was not closed before. * * @return true if connection was not closed before. */ final boolean onlyClose() { /** * Test if this build should use assertion. If NetworkAssertion == false javac will remove this * code block */ if (Assertion.NetworkAssertion) assert Thread.currentThread() == dispatcher; synchronized (guard) { if (closed) return false; try { if (socketChannel.isOpen()) { socketChannel.close(); key.attach(null); key.cancel(); } closed = true; } catch (IOException ignored) { } } return true; }
@Override public void close() throws IOException { synchronized (_monitor) { if (isClose()) { return; } if (isNew()) { _status = Status.Close; return; } logger.debug("{} start session close", _key.toString()); logout(); _status = Status.Close; _heartbeatKeep.shutdown(); if (_channel != null && _channel.isOpen()) { _channel.close(); } logger.debug("{} finish session close", _key.toString()); } }
public void stop(String test, int count, int of) throws IOException { System.err.println("Stop " + test + " " + count + " of " + of); String stop = "GET " + URIUtil.encodePath("/benchmark/stop/ " + test + " " + count + " of " + of) + " HTTP/1.1\r\n" + "Host: benchmarkControl:8080\r\n" + "Connection: close\r\n" + "\r\n"; SocketChannel control = SocketChannel.open(new InetSocketAddress("localhost", 8080)); control.write(BufferUtil.toBuffer(stop)); while (control.isOpen()) { BufferUtil.clear(responseBuf); int pos = BufferUtil.flipToFill(responseBuf); if (control.read(responseBuf) == -1) control.close(); BufferUtil.flipToFlush(responseBuf, pos); } for (int i = 0; i < client.length; i++) if (client[i] != null && client[i].isOpen()) client[i].close(); client = null; }
protected void disconnect(final long timeout, final long bannedFor, final String reason) { try { if (hasConnectionSlot.tryAcquire()) { if (unsolicited) { unsolicitedConnectSlot.release(); } else { connectSlot.release(); } } if (connected.tryAcquire()) { openConnections.decrementAndGet(); log.trace("Number of connections is now " + openConnections.get()); } if (channel.isRegistered()) { selectorChanges.add( new ChangeRequest(channel, ChangeRequest.CANCEL, SelectionKey.OP_ACCEPT, null)); selector.wakeup(); } if (channel.isOpen()) { channel.close(); log.trace("Disconnect " + channel); writes.clear(); reads.clear(); reads.add(closedMark); peerThreads.execute( new Runnable() { @Override public void run() { onDisconnect(timeout, bannedFor, reason); } }); } } catch (IOException e) { log.trace("Exception in disconnect ", e); } }
@Override protected boolean isOpenImpl() { if (socketChannel.isConnected() == false || socketChannel.isOpen() == false) { return false; } boolean ret = false; try { if (lock.isHeldByCurrentThread()) { ret = _isOpenImpl(); } else { lock.lock(); try { ret = _isOpenImpl(); } finally { lock.unlock(); } } } catch (IOException e) { Interpreter.getInstance().logWarning(e); return false; } return ret; }
/* * (non-Javadoc) * @see java.io.OutputStream#close() */ public void close() throws IOException { if (channel.isOpen()) { flush(); channel.close(); } }
/** * @param data 要发送的数据 * @param socketChannel 发往的通道 * @return 数据发送成功:true;失败:false * @throws IOException */ private boolean sendData(byte[] data, SocketChannel socketChannel) throws IOException { try { ByteBuffer dataBuffer = ByteBuffer.wrap(data); long sendSize = send(socketChannel, dataBuffer); long allSendSize = sendSize; long starttime = SystemTimer.currentTimeMillis(); while (dataBuffer.hasRemaining() && socketChannel.isOpen()) // 还有数据没写干净,一般是网络不好导致,也可能是发送和接收量太大。 { sendSize = send(socketChannel, dataBuffer); if (sendSize == 0) { Thread.sleep(5); } else { allSendSize += sendSize; } if (DebugUtils.isNeedDebug(channelContext)) { try { long endtime = SystemTimer.currentTimeMillis(); long costtime = (endtime - starttime); double speed = -1; if (costtime > 0) { speed = allSendSize / costtime; } log.error( "{} bytes was sent, {}/{}({}%), cost time: {} ms, {}bytes/ms,{}", sendSize, allSendSize, data.length, (allSendSize * 100) / data.length, costtime, speed, channelContext); } catch (Exception e) { log.error(e.getLocalizedMessage(), e); } } } StatVo.getAllSentMsgCount().incrementAndGet(); this.getProcessedMsgCount().incrementAndGet(); long endtime = SystemTimer.currentTimeMillis(); if (DebugUtils.isNeedDebug(channelContext)) { try { long costtime = (endtime - starttime); double speed = -1; if (costtime > 0) { speed = allSendSize / costtime; } log.error("cost time: {} ms, {}bytes/ms, {}", costtime, speed, channelContext); log.error( "ok sent to " + channelContext + ",total num[" + StatVo.getAllSentMsgCount().get() + "],num to this [" + getProcessedMsgCount().get() + "],waiting for send to this [" + getMsgQueue().size() + "]"); } catch (Exception e) { log.error(e.getLocalizedMessage(), e); } } return true; } catch (InterruptedException e) { return false; } }
public boolean isClosed() { return (socketChannel == null) || !socketChannel.isOpen(); }
/** {@inheritDoc} */ public boolean isOpen() { return channel.isOpen(); }
/** * The use of threaded tasks in the send/receive service makes it difficult to observer the socket * state changes. * * <p>So let's begin by writing some tests over the raw sockets. * * <p>Note that connecting and then immediately closing the socket is perfectly okay. ...with an * accept followed by a read() of -1 on the returned Socket stream. * * @throws IOException * @throws InterruptedException */ public void testDirectSockets() throws IOException, InterruptedException { // The payload size that we will use. final int DATA_LEN = 200; final Random r = new Random(); final byte[] data = new byte[DATA_LEN]; r.nextBytes(data); final byte[] dst = new byte[DATA_LEN]; // The server side receive buffer size (once we open the server socket). int receiveBufferSize = -1; final InetSocketAddress serverAddr = new InetSocketAddress(getPort(0)); // First our ServerSocket final ServerSocket ss = new ServerSocket(); try { assertTrue(ss.getChannel() == null); // bind the server socket to the port. ss.bind(serverAddr); assertTrue(ss.getChannel() == null); // figure out the receive buffer size on the server socket. receiveBufferSize = ss.getReceiveBufferSize(); if (log.isInfoEnabled()) log.info("receiveBufferSize=" + receiveBufferSize + ", payloadSize=" + DATA_LEN); if (receiveBufferSize < DATA_LEN) { fail( "Service socket receive buffer is smaller than test payload size: receiveBufferSize=" + receiveBufferSize + ", payloadSize=" + DATA_LEN); } { /* * InputStream for server side of socket connection - set below and * then reused outside of the try/finally block. */ InputStream instr = null; // Now the first Client SocketChannel final SocketChannel cs1 = SocketChannel.open(); try { /* * Note: true if connection made. false if connection in * progress. */ final boolean immediate1 = cs1.connect(serverAddr); if (!immediate1) { if (!cs1.finishConnect()) { fail("Did not connect?"); } } assertTrue(ss.getChannel() == null); /* * We are connected. */ final ByteBuffer src = ByteBuffer.wrap(data); // Write some data on the client socket. cs1.write(src); /* * Accept client's connection on server (after connect and * write). */ final Socket readSckt1 = accept(ss); // Stream to read the data from the socket on the server // side. instr = readSckt1.getInputStream(); // and read the data instr.read(dst); // confirming the read is correct assertTrue(BytesUtil.bytesEqual(data, dst)); assertTrue(ss.getChannel() == null); /* * Attempting to read more returns ZERO because there is * nothing in the buffer and the connection is still open on * the client side. * * Note: instr.read(buf) will BLOCK until the data is * available, the EOF is detected, or an exception is * thrown. */ assertEquals(0, instr.available()); // assertEquals(0, instr.read(dst)); /* * Now write some more data into the channel and *then* * close it. */ cs1.write(ByteBuffer.wrap(data)); // close the client side of the socket cs1.close(); // The server side of client connection is still open. assertTrue(readSckt1.isConnected()); assertFalse(readSckt1.isClosed()); /* * Now try writing some more data. This should be disallowed * since we closed the client side of the socket. */ try { cs1.write(ByteBuffer.wrap(data)); fail("Expected closed channel exception"); } catch (ClosedChannelException e) { // expected } /* * Since we closed the client side of the socket, when we * try to read more data on the server side of the * connection. The data that we already buffered is still * available on the server side of the socket. */ { // the already buffered data should be available. final int rdlen = instr.read(dst); assertEquals(DATA_LEN, rdlen); assertTrue(BytesUtil.bytesEqual(data, dst)); } /* * We have drained the buffered data. There is no more * buffered data and client side is closed, so an attempt to * read more data on the server side of the socket will * return EOF (-1). */ assertEquals(-1, instr.read(dst)); // read EOF // if so then should we explicitly close its socket? readSckt1.close(); assertTrue(readSckt1.isClosed()); /* * Still reports EOF after the accepted server socket is * closed. */ assertEquals(-1, instr.read(dst)); assertFalse(ss.isClosed()); assertTrue(ss.getChannel() == null); } finally { cs1.close(); } // failing to read from original stream final int nrlen = instr.read(dst); assertEquals(-1, nrlen); } /* * Now open a new client Socket and connect to the server. */ final SocketChannel cs2 = SocketChannel.open(); try { // connect to the server socket again. final boolean immediate2 = cs2.connect(serverAddr); if (!immediate2) { if (!cs2.finishConnect()) { fail("Did not connect?"); } } // Now server should accept the new client connection final Socket s2 = accept(ss); // Client writes to the SocketChannel final int wlen = cs2.write(ByteBuffer.wrap(data)); assertEquals(DATA_LEN, wlen); // verify data written. // but succeeding to read from the new Socket final InputStream instr2 = s2.getInputStream(); instr2.read(dst); assertTrue(BytesUtil.bytesEqual(data, dst)); /* * Question: Can a downstream close be detected upstream? * * Answer: No. Closing the server socket does not tell the * client that the socket was closed. */ { // close server side input stream. instr2.close(); // but the client still thinks its connected. assertTrue(cs2.isOpen()); // Does the client believe it is still open after a brief // sleep? Thread.sleep(1000); assertTrue(cs2.isOpen()); // yes. // close server stocket. s2.close(); // client still thinks it is connected after closing server // socket. assertTrue(cs2.isOpen()); // Does the client believe it is still open after a brief // sleep? Thread.sleep(1000); assertTrue(cs2.isOpen()); // yes. } /* * Now write some more to the socket. We have closed the * accepted connection on the server socket. Our observations * show that the 1st write succeeds. The second write then fails * with 'IOException: "Broken pipe"' * * The server socket is large (256k). We are not filling it up, * but the 2nd write always fails. Further, the client never * believes that the connection is closed until the 2nd write, */ { final int writeSize = 1; int nwritesOk = 0; long nbytesReceived = 0L; while (true) { try { // write a payload. final int wlen2 = cs2.write(ByteBuffer.wrap(data, 0, writeSize)); // if write succeeds, should have written all bytes. assertEquals(writeSize, wlen2); nwritesOk++; nbytesReceived += wlen2; // does the client think the connection is still open? assertTrue(cs2.isOpen()); // yes. Thread.sleep(1000); assertTrue(cs2.isOpen()); // yes. } catch (IOException ex) { if (log.isInfoEnabled()) log.info( "Expected exception: nwritesOk=" + nwritesOk + ", nbytesReceived=" + nbytesReceived + ", ex=" + ex); break; } } } /* * Having closed the input, without a new connect request we * should not be able to accept the new write since the data * were written on a different client connection. */ try { final Socket s3 = accept(ss); fail("Expected timeout failure"); } catch (AssertionFailedError afe) { // expected } } finally { cs2.close(); } } finally { ss.close(); } }
@Slow @Test public void testConnectTimeoutBeforeSuccessfulConnect() throws Exception { ServerSocketChannel server = ServerSocketChannel.open(); server.bind(new InetSocketAddress("localhost", 0)); SocketAddress address = server.getLocalAddress(); final AtomicLong timeoutConnection = new AtomicLong(); final long connectTimeout = 1000; SelectorManager selectorManager = new SelectorManager(executor, scheduler) { @Override protected EndPoint newEndPoint( SocketChannel channel, ManagedSelector selector, SelectionKey selectionKey) throws IOException { return new SelectChannelEndPoint( channel, selector, selectionKey, getScheduler(), connectTimeout / 2); } @Override protected boolean finishConnect(SocketChannel channel) throws IOException { try { long timeout = timeoutConnection.get(); if (timeout > 0) TimeUnit.MILLISECONDS.sleep(timeout); return super.finishConnect(channel); } catch (InterruptedException e) { return false; } } @Override public Connection newConnection( SocketChannel channel, EndPoint endpoint, Object attachment) throws IOException { ((Callback) attachment).succeeded(); return new AbstractConnection(endpoint, executor) { @Override public void onFillable() {} }; } @Override protected void connectionFailed(SocketChannel channel, Throwable ex, Object attachment) { ((Callback) attachment).failed(ex); } }; selectorManager.setConnectTimeout(connectTimeout); selectorManager.start(); try { SocketChannel client1 = SocketChannel.open(); client1.configureBlocking(false); client1.connect(address); long timeout = connectTimeout * 2; timeoutConnection.set(timeout); final CountDownLatch latch1 = new CountDownLatch(1); selectorManager.connect( client1, new Callback.Adapter() { @Override public void failed(Throwable x) { latch1.countDown(); } }); Assert.assertTrue(latch1.await(connectTimeout * 3, TimeUnit.MILLISECONDS)); Assert.assertFalse(client1.isOpen()); // Wait for the first connect to finish, as the selector thread is waiting in finishConnect(). Thread.sleep(timeout); // Verify that after the failure we can connect successfully. try (SocketChannel client2 = SocketChannel.open()) { client2.configureBlocking(false); client2.connect(address); timeoutConnection.set(0); final CountDownLatch latch2 = new CountDownLatch(1); selectorManager.connect( client2, new Callback.Adapter() { @Override public void succeeded() { latch2.countDown(); } }); Assert.assertTrue(latch2.await(connectTimeout * 5, TimeUnit.MILLISECONDS)); Assert.assertTrue(client2.isOpen()); } } finally { selectorManager.stop(); } }
public InetSocketAddress getLocalSocketAddress() throws IOException { if (_channel != null && _channel.isOpen()) { return (InetSocketAddress) _channel.socket().getLocalSocketAddress(); } return _localAddress; }
/** * Times out any expired connections then, if {@code selectionCount > 0}, processes the selected * keys. Removes closed connections from the connections field, and from the connections * parameter. * * @param selectionCount Number of IO Events, if 0 we were probably woken up by a close. * @param selector The selector. * @param server The server socket channel. * @param connections Map of connections. * @throws IOException Any IOException. */ protected void processNioSelections( int selectionCount, final Selector selector, ServerSocketChannel server, Map<SocketChannel, TcpNioConnection> connections) throws IOException { final long now = System.currentTimeMillis(); rescheduleDelayedReads(selector, now); if (this.soTimeout > 0 || now >= this.nextCheckForClosedNioConnections || selectionCount == 0) { this.nextCheckForClosedNioConnections = now + this.nioHarvestInterval; Iterator<Entry<SocketChannel, TcpNioConnection>> it = connections.entrySet().iterator(); while (it.hasNext()) { SocketChannel channel = it.next().getKey(); if (!channel.isOpen()) { logger.debug("Removing closed channel"); it.remove(); } else if (soTimeout > 0) { TcpNioConnection connection = connections.get(channel); if (now - connection.getLastRead() >= this.soTimeout) { /* * For client connections, we have to wait for 2 timeouts if the last * send was within the current timeout. */ if (!connection.isServer() && now - connection.getLastSend() < this.soTimeout && now - connection.getLastRead() < this.soTimeout * 2) { if (logger.isDebugEnabled()) { logger.debug( "Skipping a connection timeout because we have a recent send " + connection.getConnectionId()); } } else { if (logger.isWarnEnabled()) { logger.warn("Timing out TcpNioConnection " + connection.getConnectionId()); } SocketTimeoutException exception = new SocketTimeoutException("Timing out connection"); connection.publishConnectionExceptionEvent(exception); connection.timeout(); connection.sendExceptionToListener(exception); } } } } } this.harvestClosedConnections(); if (logger.isTraceEnabled()) { if (host == null) { logger.trace("Port " + this.port + " SelectionCount: " + selectionCount); } else { logger.trace( "Host " + this.host + " port " + this.port + " SelectionCount: " + selectionCount); } } if (selectionCount > 0) { Set<SelectionKey> keys = selector.selectedKeys(); Iterator<SelectionKey> iterator = keys.iterator(); while (iterator.hasNext()) { final SelectionKey key = iterator.next(); iterator.remove(); try { if (!key.isValid()) { logger.debug("Selection key no longer valid"); } else if (key.isReadable()) { key.interestOps(key.interestOps() - SelectionKey.OP_READ); final TcpNioConnection connection; connection = (TcpNioConnection) key.attachment(); connection.setLastRead(System.currentTimeMillis()); try { this.taskExecutor.execute( new Runnable() { @Override public void run() { boolean delayed = false; try { connection.readPacket(); } catch (RejectedExecutionException e) { delayRead(selector, now, key); delayed = true; } catch (Exception e) { if (connection.isOpen()) { logger.error( "Exception on read " + connection.getConnectionId() + " " + e.getMessage()); connection.close(); } else { logger.debug("Connection closed"); } } if (!delayed) { if (key.channel().isOpen()) { key.interestOps(SelectionKey.OP_READ); selector.wakeup(); } else { connection.sendExceptionToListener( new EOFException("Connection is closed")); } } } }); } catch (RejectedExecutionException e) { delayRead(selector, now, key); } } else if (key.isAcceptable()) { try { doAccept(selector, server, now); } catch (Exception e) { logger.error("Exception accepting new connection", e); } } else { logger.error("Unexpected key: " + key); } } catch (CancelledKeyException e) { if (logger.isDebugEnabled()) { logger.debug("Selection key " + key + " cancelled"); } } catch (Exception e) { logger.error("Exception on selection key " + key, e); } } } }
private Command readBinaryCommand() throws IOException { SocketChannel channel = this.socket.getChannel(); if (channel == null || !channel.isOpen()) { throw new IllegalStateException("cannot read from channel"); } Command cmd = null; boolean done = false; boolean read = false; while (!done) { if (!buffer.hasRemaining()) { buffer.clear(); read = true; } else if (!read) { // compact is meant for partial writes, but we want to use // it partial reads, so the new limit should be the position // after the compact operation and we want to start reading // from the beginning buffer.compact(); buffer.limit(buffer.position()); buffer.position(0); } if (read) { int bytesRead = channel.read(buffer); if (bytesRead == -1) { throw new IOException("EOF"); } buffer.flip(); } // read again if we did not read enough bytes if (buffer.limit() < HEADER_LENGTH) { buffer.compact(); read = true; continue; } int requestLength = buffer.remaining(); byte magic = buffer.get(); if (magic != REQUEST_MAGIC) { throw new IllegalStateException("Not a valid request, magic byte incorrect"); } byte opCode = buffer.get(); if (ConnectionHandler.getLogger().finerEnabled()) { String str = Command.buffertoString(buffer); ConnectionHandler.getLogger().finer("Request:" + buffer + str.toString()); } int bodyLength = buffer.getInt(AbstractCommand.TOTAL_BODY_LENGTH_INDEX); if ((HEADER_LENGTH + bodyLength) > requestLength) { // set the position back to the start of the request buffer.position(buffer.position() - 2 /*since we read two bytes*/); buffer.compact(); // ensure that the buffer is big enough if (buffer.capacity() < (HEADER_LENGTH + bodyLength)) { // allocate bigger buffer and copy the bytes to the bigger buffer ByteBuffer oldBuffer = buffer; oldBuffer.position(0); buffer = ByteBuffer.allocate(HEADER_LENGTH + bodyLength); buffer.put(oldBuffer); } read = true; continue; } cmd = Command.getCommandFromOpCode(opCode); done = true; } if (ConnectionHandler.getLogger().fineEnabled()) { ConnectionHandler.getLogger().fine("read command " + cmd); } return cmd; }