简体   繁体   English

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

[英]Maximum size of data that can be fetched from a client socket using socketChannel of nio package in java

Using SocketChannel sc =(SocketChannel)key.channel(); 使用SocketChannel sc =(SocketChannel)key.channel(); , we can fetch data from port into buffer. ,我们可以将数据从端口提取到缓冲区。
In order to receive the data continuously from port without the loss of data, how the code should be ? 为了在不丢失数据的情况下从端口连续接收数据,代码应该如何?

Here is my code 这是我的代码

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 < pos; j++ )
                        {
                            String ss =Integer.toHexString(echoBuffer.get());
                            if (ss.length() == 1)
                                System.out.print("0" + ss + " ");
                            else if (ss.length() > 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 );
  }
}

The maximum size you can read is effectively limited by the amount of memory you have. 您可以阅读的最大大小实际上受到您拥有的内存量的限制。

However you don't need to read super large blocks for efficiency. 但是,您无需读取超大块以提高效率。 You should find that 1 MB is more than enough. 你会发现1 MB就足够了。 In fact you may find that blocks of 4KB are large enough to get maximum bandwidth for a 1 Gb connection. 实际上,您可能会发现4KB的块足够大,可以为1 Gb连接获得最大带宽。

A comment on the general design: 对总体设计的评论:

There are two basic ways to write network servers. 编写网络服务器有两种基本方法。 Blocking and Nonblocking. 阻止和非阻塞。 In 2008, we had the task of implementing a high performance network server in Python. 2008年,我们的任务是在Python中实现高性能网络服务器。 After trying a couple different ways with non-blocking, we found that it was much easier and more clear to use: 在使用非阻塞尝试了几种不同的方法后,我们发现使用它更容易 ,更清晰:

  • blocking sockets 阻塞套接字
  • one thread per connection 每个连接一个线程
  • a couple of manager threads 几个经理人的话题

That way each thread could sit and wait on data until the day it died, and when it received a full packet, it would act on that. 这样每个线程都可以坐下来等待数据直到它死亡的那一天,当它收到一个完整的数据包时,它就会采取行动。

Just for consideration. 仅供考虑。

You can find some leads in this SocketChannelHandler , where are readFromChannel() function might be of interest for you. 您可以在此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();
         }
         }

As a first fix you should remove the line with key.cancel(). 作为第一个修复,您应该使用key.cancel()删除该行。 Keeping it will cancel the key and insure the key isn't considered after the first read - which will effectively stop you from reading anything afterwards. 保持它将取消密钥并确保在第一次读取后不考虑密钥 - 这将有效地阻止您在之后阅读任何内容。

When you accept a connection using NIO you can get hold of the socket and set the respective in / out buffer sizes. 当您使用NIO接受连接时,您可以获取套接字并设置相应的输入/输出缓冲区大小。

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

Since NIO makes heavy use of the OS's network stack this is just a hint. 由于NIO大量使用操作系统的网络堆栈,这只是一个提示。 All this is actually very well documented in the Socket JavaDoc 所有这些实际上都在Socket JavaDoc中有很好的记录

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM