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

Я пытаюсь закодировать приложение для связи между сервером и клиентом, которое использует два отдельных потока: один для ввода и один для вывода. Однако у меня странная проблема с «тупиком»: когда один поток читает ввод, но клиент ничего не отправил, поток останавливается (поскольку он ожидает ввода). Однако по какой-то причине, пока входной поток заблокирован, выходной поток не может ничего писать.

Это показано в этом примере кода:

import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;

public class TestServer {
    public static void main(String... args) throws IOException {

        /* Creates a server socket that lurks about our port waiting for connections */
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.configureBlocking(false);
        serverChannel.socket().bind(new InetSocketAddress(4114));


        while(true){
            SocketChannel connectionChannel = serverChannel.accept();
            if(connectionChannel != null){
                final Socket connection = connectionChannel.socket();


                new Thread(){
                    public void run(){
                        try {
                            System.out.println("READING");
                            System.out.flush();
                            // If the next line is commented out, nothing blocks
                            connection.getInputStream().read();
                            System.out.println("DONE READING");
                            System.out.flush();
                        } catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                }.start();

                new Thread(){
                    public void run(){
                        try {
                            System.out.println("WRITING");
                            System.out.flush();
                            new DataOutputStream(connection.getOutputStream()).writeBytes("AUGH!!!");
                            //connection.getOutputStream().write(5);
                            System.out.println("DONE WRITING");
                            System.out.flush();
                        } catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                }.start();

                break;
            }
        }
    }
}

И код клиента:

import java.net.*;
import java.io.*;

public class TestClient {

    public static void main(String... args) throws IOException {
        Socket connection = new Socket("127.0.0.1", 4114); 
        while(true){
            System.out.println(connection.getInputStream().read());
        }
    }

}

Пример кода выше блокирует, но если строка на сервере закомментирована, это не так. Это почему? Ограничен ли сокет только одновременным ожиданием ввода/вывода? Что происходит?


person Nifty    schedule 17.03.2011    source источник
comment
Я удивлен таким поведением, но мне кажется странным обрабатывать ввод и вывод для одного клиента в двух отдельных потоках. Большинство систем на основе потоков используют один поток для каждого клиента. (И я думал, что одной из важных функций вызовов nio было то, что он позволял вам писать серверы без использования потоков — это потокобезопасно?)   -  person sarnold    schedule 18.03.2011
comment
Я также заметил, что если я переключаю строку с DataOutputStream на строку, которая просто использует прямой OutputStream, все начинает работать. Отправляет ли DataOutputStream какие-то заголовки, которые все портят? Что происходит?   -  person Nifty    schedule 18.03.2011
comment
Я считаю, что DataOutputStream не отправляет никаких данных заголовка, ObjectOutputStream, безусловно, отправляет, но тем не менее это должно повлиять на вашу проблему.   -  person MeBigFatGuy    schedule 18.03.2011


Ответы (1)


Я не уверен, почему вы видите это, но это как-то связано с использованием каналов.

Если заменить этот код на

ServerSocket ss = new ServerSocket(4114);
Socket connection = ss.accept();

это будет работать так, как вы хотите.

person MeBigFatGuy    schedule 17.03.2011