ServerSocket 및 소켓을 사용할 때 BufferedReader가 중단되고 연결이 제대로 형성되지 않는 것처럼 보입니다.

J_mie6

편집 : 서버 코드에 줄을 추가하여 코드 아래의 실수를 수정했습니다.

게임을 위해 한 컴퓨터에서 다른 컴퓨터로 데이터를 보낼 수있는 소켓 코드를 작성하려고합니다 (단순함을 위해 많은 데이터를 보낼 필요가없는 tic-tac-toe로 생각할 수 있습니다. 몇 개의 숫자). 이 I를 달성하기 위해 두 개의 클래스를 작성했다 Server하고 Client. 현재는 포트 1234를 사용하여 로컬 호스트를 통해 테스트하고 있으며 프로그램의 단일 인스턴스 만 사용하고 있습니다 (두 인스턴스를 사용하려고 할 때 동일한 문제가 발생하지만).

먼저 여기에 코드가 있습니다. 그런 다음 문제에 대해 더 자세히 살펴볼 수 있으며, 무엇이 잘못되었는지 확인하기 위해 수행 한 테스트는 무엇입니까?

public class Server
{
    private ServerSocket server;
    private Socket socket;

    private Client socketHandler;

    private static final int DEFAULT_PORT = 1234;

    public Server() { this(DEFAULT_PORT); }
    public Server(int port)
    {
        Thread thread = new Thread()
        {
            public void run()
            {
                try
                {
                    System.out.println("Attempting to Establish Connection");
                    server = new ServerSocket(port);
                    socket = server.accept();
                    socketHandler = new Client(port, socket); //THIS LINE ADDED
                    System.out.println("Server Online!");
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        };

        thread.setDaemon(true);
        thread.start();
    }

    //ADJUSTED
    Client getSocketHandler()
    {
        return socketHandler;
    }

    public void kill()
    {
        try
        {
            if (socket != null) socket.close();
            if (server != null) server.close();
        }
        catch(IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            socket = null;
            server = null;
        }
    }
}

public class Client
{
    public static final int DEFAULT_PORT = 1234;
    public static final String DEFAULT_HOST = "localhost";
    private static final String THUMP_THUMP = "thump thump";
    private static final int PULSE = 1000;

    private int port;
    private String ip;

    private Socket socket;
    private BufferedReader input = null;
    private PrintWriter output = null;

    boolean closed = true;

    String data = "";

    public Client() { this(DEFAULT_PORT, DEFAULT_HOST, null); }
    public Client(int port) { this(port, DEFAULT_HOST, null); }
    public Client(int port, String ip) { this(port, ip, null); }
    public Client(int port, Socket server) { this(port, DEFAULT_HOST, server); }
    public Client(String ip) { this(DEFAULT_PORT, ip, null); }
    public Client(String ip, Socket server) { this(DEFAULT_PORT, ip, server); }
    public Client(Socket server) { this(DEFAULT_PORT, DEFAULT_HOST, server); }
    public Client(int port, String ip, Socket server)
    {
        socket = server;
        this.ip = ip;
        this.port = port;

        Thread thread = new Thread()
        {
            public void run()
            {                
                try
                {
                    initialise(server);
                    String line;
                    startHeartbeat();
                    while (isClosed()) {} //first it is closed, lets wait for it to open before we start waiting for it to close!
                    System.out.println("We are about to listen!");
                    while (!isClosed())
                    {
                        System.out.println("pre-read"); //this line was used to determine that the code was hanging on the next line
                        line = input.readLine(); //offending line
                        System.out.println("post-read"); //this line was used to determine when the block was lifted
                        if (line != null)// || line != THUMP_THUMP)
                        {
                            System.out.println(line);
                            data += line + "\n";
                        }
                    }
                    System.out.println(data);
                    kill();
                    System.out.println("Connection Closed!");
                }
                catch (SocketException e)
                {
                    e.printStackTrace();
                    System.out.println("Server closed!");
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        };

        thread.setDaemon(true);
        thread.start();
    }

    private void initialise(Socket server)
    {
        try
        {
            if (server == null) socket = new Socket(ip, port);
            input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
        }
        catch (IOException e) { e.printStackTrace(); }
    }

    public boolean post(String text)
    {
        synchronized(this)
        {
            output.println(text);
            output.flush();
            return !output.checkError();
        }
    }

    public void kill()
    {
        try
        {
            if (input != null) input.close();
            if (socket != null) socket.close();
        }
        catch(IOException e) { e.printStackTrace(); }
        finally
        {
            input = null;
            socket = null;
        }
    }

    public void killOutputStream()
    {
        try
        {
            if (output != null) output.close();
        }
        catch (Exception e) { e.printStackTrace(); }
        finally
        {
            output = null;
        }
    }

    //////////////////////////////////
    ///////// Socket Control /////////
    //////////////////////////////////

    synchronized boolean isClosed()
    {
        return closed;
    }

    synchronized void setClosed(boolean b)
    {
        closed = b;
    }

    //We need to make sure that the socket is still online, to ensure the reading stops when the connection closes.
    void startHeartbeat()
    {
        Thread heartbeat = new Thread()
        {
            public void run()
            {
                while (output != null)
                {
                    setClosed(post(THUMP_THUMP) ? false : true); //post returns true on success
                    synchronized(this)
                    {
                        try
                        {
                            this.wait(PULSE);
                        }
                        catch (InterruptedException e) {}
                    }
                }
                setClosed(true);
            }
        };
        heartbeat.setDaemon(true);
        heartbeat.start();
    }
}

문제

클라이언트가 시작되면 (서버를 만든 후) 전송 된 데이터 (또는 하트 비트)를 읽지 못합니다. 실제로 코드는 line = input.readLine()읽기 스레드 (지금부터 문제가되는 줄이라고 함)에서 지나 가지 않습니다. , 보이는 것을 제외하고는 서버 연결이 끊어 질 때까지 (아래 참조).

다음은 정기 테스트의 순서입니다.

Server()가 호출되고 결과 ServerserverConnection변수에 저장되고 Client(serverConnection != null ? serverConnection.getSocket() : null)호출되고 새 값 Client이에 저장됩니다 clientConnection.

우리는 다른 데이터 요구가 전송되지 수있는 하트 비트를 사용하여 작업하고, 서버를 호출하여 종료 여부를 테스트 할 수 있기 때문에 serverConnection.kill()다음과 clientConnection.killOutputStream()약간의 시간 경과를시키는 후.

결과는 다음과 같습니다.

Attempting to Establish Connection Server Online! 
We are about to listen!

Connection Closed!

여기서 빈 줄은 연결 과정에서 수신 된 null이 아닌 데이터를 나타냅니다. 즉, 아무것도 없습니다.

나는 이것을 기대한다 :

Attempting to Establish Connection
Server Online!
We are about to listen!
thump thump
thump thump
thump thump (and so on, every second)
Connection closed!

동일한 테스트 형식 (6 번인 특수한 경우 제외)으로 코드를 주석 처리하거나 약간 변경하여 다른 테스트를 수행하는 데 시간을 보냈고 다음과 같이 관찰했습니다.

관찰

  1. 소켓이 닫히고 출력 스트림이 닫힐 때만 프로그램이 문제가되는 라인을지나 이동합니다.
  2. readline()방법은 (곧 하트 비트 삭감 그것을 해제하기 전에) 프로세스를 시작 그것은 스트림 아무것도, 심지어를 감지하지 않습니다 THUMP_THUMP.
  3. 소켓이 닫혀 있지만 출력 스트림이 닫히지 않으면 readline()메서드가 처리를 시작하고 아무것도 감지하지 않고 하트 비트가이를 차단합니다. SocketException예상 할 수 있지만 아니요 .
  4. 소켓이 닫히지 않고 출력 스트림 만 닫히면 SocketException소켓이 닫 혔음을 알리는 a 가 트리거됩니다.
  5. netstat -an명령 프롬프트에서 사용 했으며 서버가 시작될 때 포트 1234는 LISTENING입니다. 클라이언트가 연결되면 여전히 LISTENING이며 연결이 없음을 의미합니다.
  6. 포트 1234를 통해 자체적으로 연결하기 위해 일부 파이썬 코드를 설정했지만 파이썬 코드에서 실수를하여 서버가 닫히지 않고 여전히 열려있었습니다. 그래서 저는 자바 클라이언트를 서버에 연결하고 무슨 일이 일어나는지보기로 결정했습니다. Client(null)호스트가 아닌 클라이언트 코드를 실행하여이 작업을 수행했습니다 . 그 결과 포트가 ESTABLISHED를 읽게되었고 파이썬 서버는 "쿵쿵"소리를 내고 자바 코드가이를 성공적으로 읽었습니다. 매달리지 않고 완벽하게 작동했습니다.

이것은 파이썬 서버가 Java 클라이언트와 성공적으로 통신 할 수 있었지만 Java 클라이언트가 Java 서버와 통신 할 수 없기 때문에 문제가 서버 코드에 있다고 믿게합니다.

이 테스트를 수행하기 전에 나는 그것이 잘못 되었다고 믿고 클라이언트 코드에 집중했습니다 . 비슷한 증상을 가진 여기에서 찾은 모든 질문 ( 여기 , 여기여기 참조 )은 솔루션을 작성하여 공백으로 표시되었습니다 (대부분 출력 스트림이 플러시되지 않거나 \ n 생략 되었기 때문). 내가 실패하지 않았거나 내 문제를 해결하지 못하는 솔루션 이므로이 경우 심장 박동을 위해 제거되었습니다). 원래는 떨어져 내 코드를 기반으로 기사.

4 일 동안이 문제를 해결하려고 노력한 후 무엇을해야할지 모르겠습니다. 여기서 무엇을 놓치고 있습니까? 서버 코드가 예상대로 작동하지 않는 이유는 무엇입니까? 누구든지 내 코드에 대한 설명이 더 필요하면 요청하십시오!

참고로 테스트 코드는 javafx (fxml이 아님)로 작성된 간단한 최소한의 GUI를 통해 실행됩니다. 이것이 문제인지 아닌지 확신합니다. Python과 함께 작동하기 때문에 그렇지 않습니다. 섬기는 사람. 이 코드는 Java 8로 컴파일되었습니다.

TheJavaCoder16

서버 측에서 입력 / 출력 처리가 없다는 점을 고려할 때 input.readLine ()보다 더 멀리 갈 것이라고 생각하는 이유에 대해 약간 혼란 스럽습니다 ....

클라이언트 / 서버 연결은 테니스 게임과 같습니다. 한 쪽이 다른 쪽이 공을받은 다음 다시 서비스해야하기 때문입니다 (다른 정보 일 수 있음). 서버 측은 시작 하트 비트 방법에서 수신 한 입력을 처리 한 다음 응답을 다시 보내야합니다. input.readLine () 함수는 다른 쪽 끝에서 데이터를받을 때까지 스레드를 차단하므로 코드는 여기서 멈추고 서버가 "테니스 공"을 다시 보낼 때까지 기다립니다. 서버 클래스에서 심장 박동 입력을 처리하고 데이터 문자열을 클라이언트로 다시 보내는 입력 및 출력 스트림을 추가해야합니다.

섬기는 사람:

OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
String response = "thump thump";

while(true){
    is.read();
    os.write(response.getBytes());
    os.flush();
}

이 예제에서 클라이언트는 변경되지 않고 위의 코드를 서버에 추가하기 만하면됩니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

Related 관련 기사

뜨겁다태그

보관