Advenced Socket Programming - устраняет дополнительную проблему передачи данных клиенту - PullRequest
1 голос
/ 10 августа 2010

Здесь Один сервер и один клиент. И связь поддерживалась по выбору канала. лайк-- Сервер ---

  SelectionKey selectKey = channel.register(this.selector,

        SelectionKey.OP_ACCEPT);

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

    Set<SelectionKey> selectedKeys = this.selector.selectedKeys();

    Iterator<SelectionKey> iterator = selectedKeys.iterator();

    while (iterator.hasNext()) {

        SelectionKey key = iterator.next();

        iterator.remove();

        if (key.isAcceptable()) {

            ServerSocketChannel nextChannel = (ServerSocketChannel) key

                        .channel();
            SocketChannel newChannel = nextChannel.accept();

            newChannel.configureBlocking(false);

            if (!newChannel.isRegistered()) {

                SelectionKey selectionKey = newChannel.register(

                     this.selector, SelectionKey.OP_READ

                | SelectionKey.OP_WRITE);

                selectionKey.attach(newChannel);

            }

        } else if (key.isWritable()) {

             SocketChannel attachment1 = (SocketChannel)key.attachment();
             ByteBuffer writeBuffer = ByteBuffer.wrap("Hello".getBytes());

                attachment1.write(writeBuffer);

                System.out.print("Written");
            }
         }
      } 

Клиент:

   InetSocketAddress isa = new InetSocketAddress(InetAddress
            .getLocalHost(), 4444);
    SocketChannel sc = null;

    try {

        while (true) {

            Thread.sleep(10000);
            sc = SocketChannel.open();
            sc.connect(isa);
            ByteBuffer byteBuffer = ByteBuffer.allocate(BUFSIZE);
            int nbytes = sc.read(byteBuffer);
            byteBuffer.flip();
            dbuf.flip();
            CharBuffer cb = decoder.decode(byteBuffer);
            System.out.println(isa + " : " + cb);

        }

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

Ответы [ 2 ]

5 голосов
/ 10 августа 2010

Так работают TCP-сокеты - они представляют собой поток байтов, а не последовательность сообщений.

Вам потребуется разработать протокол более высокого уровня, чтобы получатель мог повторно обнаружитьграницы сообщения после получения байтов.

1 голос
/ 11 августа 2010

В вашем коде есть очень странные вещи. Не удивительно, что он плохо себя ведет.

  1. Канал, принятый от ServerSocketChannel, является совершенно новым, поэтому проверка того, зарегистрирован он или нет, - пустая трата времени. Не зарегистрировано.

  2. Присоединение канала к клавише выбора не имеет смысла: у SelectionKey уже есть метод channel (). Вложение должно быть своего рода объектом контекста сеанса, содержащим буферы для сеанса и любое другое состояние, которое вам нужно сохранить.

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

  4. Ваш сервер не проверяет результат write (). Это может быть что угодно от нуля до buffer.remaining ().

  5. Выделение нового байтового буфера для чтения чрезвычайно расточительно. Они относительно дороги в создании. Вы должны создать по одному на канал и использовать его для жизни канала. Может быть два, один для чтения и один для письма.

  6. Вы никогда не закрываете SocketChannel в клиенте, поэтому вы перегружаете сервер незанятыми соединениями.

  7. Вы неправильно используете OP_WRITE. OP_WRITE всегда готов, кроме случаев, когда буфер отправки сокета заполнен. Вы должны (а) просто написать, когда вы готовы, (б) проверить возвращаемое значение, (в) зарегистрировать канал для OP_WRITE, если он равен нулю, (d) когда вы получите OP_WRITE, сделать запись и отмените регистрацию OP_WRITE, если вы не получили еще один ноль. В настоящее время вы также перегружаете сервер, заставляя его писать на каждом канале, и вы даже не читаете все эти записи с вашим клиентом.

  8. После последовательности flip () / decode () вы должны сжать () буфер, если он будет использоваться повторно, как и должно быть.

...