使用java中的nio包的socketChannel从客户端套接字获取的最大数据大小

使用SocketChannel sc =(SocketChannel)key.channel(); ,我们可以将数据从端口提取到缓冲区。
为了在不丢失数据的情况下从端口连续接收数据,代码应该如何?

这是我的代码

 import java.io.*; import java.net.*; import java.nio.*; import java.nio.channels.*; import java.util.*; public class MultiPortEcho { private int ports[]; private ByteBuffer echoBuffer = ByteBuffer.allocate(32000); public MultiPortEcho( int ports[] ) throws IOException { this.ports = ports; go(); } private void go() throws IOException { // Create a new selector Selector selector = Selector.open(); // Open a listener on each port, and register each one // with the selector for (int i=0; i<ports.length; ++i) { ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.configureBlocking( false ); ServerSocket ss = ssc.socket(); InetSocketAddress address = new InetSocketAddress( ports[i] ); ss.bind( address ); SelectionKey key = ssc.register( selector, SelectionKey.OP_ACCEPT ); System.out.println( "Going to listen on "+ports[i] ); } while (true) { int num = selector.select(); System.out.println("num::::"+num); Set selectedKeys = selector.selectedKeys(); Iterator it = selectedKeys.iterator(); while (it.hasNext()) { SelectionKey key = (SelectionKey)it.next(); if ((key.readyOps() & SelectionKey.OP_ACCEPT)== SelectionKey.OP_ACCEPT) { // Accept the new connection ServerSocketChannel ssc = (ServerSocketChannel)key.channel(); SocketChannel sc = ssc.accept(); sc.configureBlocking( false ); // Add the new connection to the selector SelectionKey newKey = sc.register(selector,SelectionKey.OP_READ); it.remove(); System.out.println( "Got connection from "+sc ); } else if ((key.readyOps() & SelectionKey.OP_READ)== SelectionKey.OP_READ) { // Read the data SocketChannel sc =(SocketChannel)key.channel(); System.out.println("sc::::"+sc); // data to fetched from channel and dump into the datatbase int bytesEchoed = 0; //while(true) { echoBuffer.clear(); int r = sc.read(echoBuffer); System.out.println("r:::" + r); /*int pos=echoBuffer.position(); System.out.println("pos:::" +pos);*/ if (r == -1) { //echoBuffer.flip(); echoBuffer.rewind(); byte[] array = new byte[100000]; while (echoBuffer.hasRemaining()) { int n = echoBuffer.remaining(); System.out.println("size:" + n); echoBuffer.get(array,0,n ); System.out.println(new String(array,0,n)); key.cancel(); it.remove(); } } /*int pos=echoBuffer.position(); System.out.println("pos:::" + pos); if(r<=0) { echoBuffer.flip(); for (int j = 0; j  2) System.out.print(ss.substring(6) + " "); else System.out.print(ss + " "); } break; } echoBuffer.flip(); sc.write( echoBuffer ); bytesEchoed += r;*/ } //System.out.println( "Echoed "+bytesEchoed+" from "+sc ); //it.remove(); } } //System.out.println( "going to clear" ); // selectedKeys.clear(); //System.out.println( "cleared" ); } } static public void main( String args[] ) throws Exception { FileOutputStream fileoutputstream = new FileOutputStream("MultiPort.txt", false); PrintStream printstream = new PrintStream(fileoutputstream); System.setOut(printstream); if (args.length<=0) { System.err.println( "Usage: java MultiPortEcho port [port port ...]" ); System.exit( 1 ); } int ports[] = new int[args.length]; for (int i=0; i<args.length; ++i) { ports[i] = Integer.parseInt( args[i] ); } new MultiPortEcho( ports ); } } 

您可以阅读的最大大小实际上受到您拥有的内存量的限制。

但是,您无需读取超大块以提高效率。 你会发现1 MB就足够了。 实际上,您可能会发现4KB的块足够大,可以为1 Gb连接获得最大带宽。

对总体设计的评论:

编写网络服务器有两种基本方法。 阻止和非阻塞。 2008年,我们的任务是在Python中实现高性能网络服务器。 在尝试使用非阻塞的几种不同方法后,我们发现使用它更容易 ,更清晰:

  • 阻塞套接字
  • 每个连接一个线程
  • 几个经理人主题

这样每个线程都可以坐下来等待数据直到它死亡的那一天,当它收到一个完整的数据包时,它就会采取行动。

仅供考虑。

您可以在此SocketChannelHandler中找到一些潜在客户,其中readFromChannel()函数可能对您有用。

  public void readFromChannel() { try { [...] if (readBuffer != null) { readBuffer.flip(); receivingBroker.broker(readBuffer, false); if (readBuffer != null) { readBuffer.clear(); readBuffer = null; } } if (readBuffer == null || !readBuffer.hasRemaining()) { getThread().removeInterestOp(this, SelectionKey.OP_READ); getThread().addInterestOp(this, SelectionKey.OP_WRITE); } if (receivingBroker.isClosed()) { if (getChannelListener() != null) { getChannelListener().readFinished(this); } } } catch (Exception e) { e.printStackTrace(); } } 

作为第一个修复,您应该使用key.cancel()删除该行。 保持它将取消密钥并确保在第一次读取后不考虑密钥 – 这将有效地阻止您在之后阅读任何内容。

当您使用NIO接受连接时,您可以获取套接字并设置相应的输入/输出缓冲区大小。

 socketChannel.socket().setReceiveBufferSize(512); socketChannel.socket().setSendBufferSize(16); 

由于NIO大量使用操作系统的网络堆栈,这只是一个提示。 所有这些实际上都在Socket JavaDoc中有很好的记录