Максимальный размер данных, которые могут быть получены из клиентского сокета с помощью socketChannel пакета nio в Java - PullRequest
3 голосов
/ 13 февраля 2009

Используя 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 < 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 );
  }
}

Ответы [ 5 ]

2 голосов
/ 04 апреля 2009

Максимальный размер, который вы можете прочитать, эффективно ограничен объемом вашей памяти.

Однако вам не нужно читать сверхбольшие блоки для эффективности. Вы должны обнаружить, что 1 МБ более чем достаточно. На самом деле вы можете обнаружить, что блоки размером 4 КБ достаточно велики, чтобы получить максимальную пропускную способность для соединения 1 ГБ.

1 голос
/ 13 февраля 2009

Комментарий к общему дизайну:

Существует два основных способа написания сетевых серверов. Блокировка и неблокирование. В 2008 году перед нами стояла задача реализовать высокопроизводительный сетевой сервер на Python. Попробовав несколько разных способов с неблокированием, мы обнаружили, что это намного проще и более понятно в использовании:

  • блокирующие розетки
  • одна нить на соединение
  • пара веток менеджера

Таким образом, каждый поток может сидеть и ждать данных до того дня, когда он умрет, и когда он получит полный пакет, он будет действовать на это.

Только для рассмотрения.

0 голосов
/ 04 апреля 2009

Когда вы принимаете соединение с помощью NIO, вы можете взять сокет и установить соответствующие размеры буфера ввода / вывода.

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

Поскольку NIO интенсивно использует сетевой стек ОС, это всего лишь подсказка. Все это на самом деле очень хорошо задокументировано в Socket JavaDoc

0 голосов
/ 04 апреля 2009

В качестве первого исправления вы должны удалить строку с помощью key.cancel (). Сохранение его отменяет ключ и гарантирует, что ключ не будет считаться после первого чтения, что фактически не даст вам ничего прочитать после этого.

0 голосов
/ 13 февраля 2009

Вы можете найти некоторые выводы в этом 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();
         }
         }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...