为什么我第一次尝试写入Socket时我的连接重置?

时间:2016-11-17 07:07:48

标签: java sockets concurrency

当我运行我相当简单的TCP服务器时,我注意到第一次尝试连接并发送对象时,我收到连接重置错误。如果我保持服务器运行但让客户端再次发送它一切正常。我在这里不知所措,是什么导致了这种行为?

客户端:

      for (int i = 0; i < 3; i++) {
        Socket s = new Socket("192.168.0.10", 9750);
        SysIO.print("Connected: " + s.isConnected());
        ObjectOutputStream oos = new ObjectOutputStream(
           new BufferedOutputStream(s.getOutputStream()));
        Object obj = new OneMessage("Hi there: " + i);
        oos.writeObject(obj);
        oos.flush();

        sleep(1000); // <-- turns error on and off  :/
    }

服务器:

    try (ServerSocket incomingSocket = new ServerSocket(mPort)) {
        SysIO.print("Game Server started...");
        incomingSocket.setSoTimeout(mTimeout);

        while (mRunning) {
            Socket clientConnection = null;
            try {
                clientConnection = incomingSocket.accept();
                clientConnection.setSoTimeout(3000);

                final Socket connection = clientConnection;
                Thread requestHandlingThread = new Thread(() -> {
                    mRequestHandler.handleRequest(connection);
                });
                requestHandlingThread.start();

            } catch (SocketTimeoutException ste) {
                SysIO.print("TCP timeout...");
            } catch (IOException ex) {
                Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    } catch (BindException ex) {
        SysIO.print("Could not bind: " + ex.getMessage());
    } catch (IOException ex) {
        SysIO.print("There was a problem with IO in TCP Server: " + ex.getMessage());
        Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null, ex);
    }

请求处理程序:

public void handleRequest(Socket aRequest) {

    try {
        SysIO.print("Connected: " + aRequest.isConnected());
        ObjectInputStream ois = new ObjectInputStream(
            new BufferedInputStream(aRequest.getInputStream()));
        GameMessage message = (GameMessage) ois.readObject();

        aRequest.close();


        SysIO.print("Received: " + message.getType());
    } catch (IOException | ClassNotFoundException ex) {
        SysIO.print("IO exception: " + ex.getMessage());
        Logger.getLogger(SimpleHandler.class.getName()).log(Level.SEVERE, null, ex);
    }

}

我在每次请求后尝试关闭而不是从服务器关闭套接字。

如果我在没有循环的情况下运行客户端它似乎工作,我认为它最初失败但我无法重新创建它。

如果我尝试在循环中运行客户端,则第一次运行客户端时所有连接都将失败,但如果我重新启动客户端,则所有连接都将成功。

使用sleep(1000)暂停上面的循环将使所有连接成功。服务器无法处理快速连接尝试是否那么简单?我希望将请求处理放在单独的线程中将启用此功能。但为什么循环中的第一个连接也会失败?

此致 基督教

1 个答案:

答案 0 :(得分:0)

所以最后我加入了这样的事情:

客户端:

try {
    Socket connection = new Socket(mHostAddress, mHostPort);
    connection.setSoTimeout(mTimeOut);
    ObjectOutputStream outgoing = new ObjectOutputStream(
            new BufferedOutputStream(connection.getOutputStream()
            )); // <-- Opening output stream first in client (opposite to server)
    outgoing.writeObject(mMessage);
    outgoing.flush();
    outgoing.close(); // <-- closing the stream as per EJP's comment
} catch (IOException ex) {
    System.out.print("IOException in TCPSender: " + ex.getMessage());
}

服务器:

ExecutorService pool = Executors.newFixedThreadPool(mClientThreads);
try (ServerSocket server = new ServerSocket(mPort)) {
    while (mRunning) {
        final Socket client = server.accept();
        client.setSoTimeout(mTimeOut);
        pool.execute(() -> {
            mMessageHandler.handle(client); // mMessageHandler = NetworkMessageHandler
        });
    }
} catch (IOException ex) {
    System.out.println("IO Exception occurred in TCPServer: "
            + ex.getMessage());
} finally {
    System.out.println("Server stopped...");
}

NetworkMessageHandler

try {
    ObjectInputStream input = new ObjectInputStream(
            new BufferedInputStream(aClient.getInputStream()) // Input first in server
    );
    NetworkMessage message = (NetworkMessage) input.readObject();
    input.close(); // <-- closing stream
    aClient.close(); // <-- making sure to close the Socket connection to client

    act(message, sendersIP); <-- acting on the message from client

} catch (IOException ex) {
    System.out.println("An IO exception occurred "
            + "in NetworkMessageHandler: " + ex.getMessage());
} catch (ClassNotFoundException ex) {
    System.out.println("Could not recreate the sent class: "
            + ex.getMessage());
}

我确保我没有错过关闭我的溪流和插座,并按照this oracle tutorial提示了一些提示。

此致 基督教