Запись в SocketChannel на Java неожиданно повторяется - PullRequest
0 голосов
/ 17 апреля 2011

Я уже некоторое время пытаюсь работать с NIO SocketChannels, и я в тупик, когда пишу в SocketChannel.Следующий код от моего клиента:

    public class nbClient {

/**
 * @param args
 */
static int id;
static int delay = 1000;
static int port;
public static void main(String[] args) throws Exception{

    if (args.length > 0){
        id = Integer.parseInt(args[0]);
        port = Integer.parseInt(args[1]);

    }
    else{
        id = 99;
        port = 4444;
    }
    // Create client SocketChannel
    SocketChannel client = SocketChannel.open();

    // nonblocking I/O
    client.configureBlocking(false);

    // Connection to host port 8000
    client.connect(new java.net.InetSocketAddress("localhost",port));       

    // Create selector
    Selector selector = Selector.open();

    //SelectionKey clientKey = client.register(selector, SelectionKey.OP_CONNECT);
    SelectionKey clientKey = client.register(selector, client.validOps());

    // Waiting for the connection

    while (selector.select(1000) > 0) {

      // Get keys
      Set keys = selector.selectedKeys();
      Iterator i = keys.iterator();

      // For each key...
      while (i.hasNext()) {
        SelectionKey key = (SelectionKey)i.next();

        // Remove the current key
        i.remove();      

        // Get the socket channel held by the key
        SocketChannel channel = (SocketChannel)key.channel();

        // Attempt a connection
        if (key.isConnectable()) {

          // Connection OK
          System.out.println("Server Found");

          // Close pendency connections
          if (channel.isConnectionPending())
            channel.finishConnect();
          //channel.close();

          channel.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ);

        }
        if (key.isWritable()){
            System.out.println("Ready for writing");

              // Write on the buffer
              ByteBuffer buffer = null;
              int counter = 0;                
                buffer = 
                  ByteBuffer.wrap(
                    new String(" This is a very long message from Client " + id + " that should exceed the bufer by a bit").getBytes());
                int outBytes = channel.write(buffer);
                System.out.println(channel.isConnectionPending());
                System.out.println(outBytes);
                buffer.clear();
                counter++;

        }

        if (key.isReadable()){
            System.out.println("Ready for reading");
        }

      }
    }

}

}

Моя проблема связана с попыткой записи на канал.Всякий раз, когда эта часть кода выполняется, она многократно повторяется, записывая данные во время каждой итерации, не дожидаясь, пока сервер ее обработает.Когда я запускаю отладчик с моим кодом, сервер, похоже, может перехватить и обработать передачу (клиент продолжает пересылать запросы, но, по крайней мере, сервер отображает переданные байты).Когда код просто запускается как есть без каких-либо принудительных задержек, клиентский код запускается пару десятков раз, после чего соединение прерывается, а сервер, по-видимому, игнорирует передачу.Вот мой раздел кода сервера - обратите внимание, что он запускается из класса Runnable:

try {
            readwriteSelector.select();
            // Once the event occurs, get keys
            Set<SelectionKey> keys = readwriteSelector.selectedKeys();
            Iterator<SelectionKey> i = keys.iterator();     


            // For each keys...
            while(i.hasNext()) {

              // Get this most recent key
              SelectionKey key = i.next();      

              if (key.isReadable()){
                  System.out.println("Is Readable");
              }

              if (key.isWritable()){
                  System.out.println("Is Writable");
                  SocketChannel client = (SocketChannel) key.channel();
                  buf.clear();

                  int numBytesRead = client.read(buf);

                  if (numBytesRead == -1){
                        client.close();
                    }
                    else {
                        buf.flip();
                        byte[] tempb = new byte[buf.remaining()];

                        buf.get(tempb); 

                        String s = new String(tempb);

                        System.out.println(s);
                    }
              }

              // Remove the current key
              i.remove();
              //readwriteSelector.selectedKeys().clear();
            }


        } catch (IOException e) {
            e.printStackTrace();
        }

Я знаю, что это хороший код, но на данный момент я не могу точно определить, где проблема.Может кто-нибудь понять, почему клиент и сервер, по-видимому, не могут общаться, несмотря на тот факт, что передача происходит нормально, если я задерживаюсь?

Спасибо.

1 Ответ

2 голосов
/ 17 апреля 2011

Метод сервера read() также должен быть в цикле.SocketChannel.read() будет считывать до размера буфера, но может читать меньше, включая 0 байтов.

Заменить начальный блок

int numBytesRead = client.read(buf);

на

   StringBuilder msg = new StringBuilder();
   for (;;) {
    int numBytesRead = client.read(buf);
    if (numBytesRead==-1)
        break;
    if (numBytesRead>0) {
        buf.flip();
        byte[] tempb = new byte[buf.remaining()];
        buf.get(tempb); 
        String s = new String(tempb);
        msg.append(s);
    }
   }
   client.close();
   System.out.prinltn(msg);
...