有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

socket仅在Java TCP服务器输出上检查客户端断开连接

我有一个Java TCP服务器,当客户端连接到它时,它每30秒向客户端输出一条消息。严格要求客户端不向服务器发送任何消息,并且服务器不向客户端发送30秒间隔消息以外的任何数据

当我断开客户端连接时,服务器在下次尝试写入客户端之前不会意识到这一点。因此,服务器识别断开连接可能需要30秒

我想做的是每隔几秒钟检查一次断开连接,而不必等待,但我不确定如何执行此操作,因为a)服务器没有从客户端接收到数据,b)服务器无法发送任何其他数据。有人能解释一下吗?谢谢


共 (2) 个答案

  1. # 1 楼答案

    如果您管理多个客户端,那么我猜您将使用非阻塞套接字(如果没有,则考虑使用非阻塞)。您可以使用选择器监视所有连接的套接字,以检查它们是否可读或可写,或者该套接字上是否存在错误。当某些客户端断开连接时,选择器将标记该套接字并返回。 有关更多帮助,请使用谷歌“套接字选择函数”

  2. # 2 楼答案

    即使您的服务器没有从客户端“接收”,客户端套接字上的非阻塞读取也会告诉您没有要读取的内容(如您所期望的),或者客户端已断开连接

    如果您使用的是NIO,那么只需使用一个非阻塞Selector循环(带有非阻塞套接字),并且只需在30秒的标记上进行写入。如果SelectionKey是可读的,并且SocketChannel上的读取返回-1,则您知道客户端已断开连接

    编辑:另一种阻塞方法是只需选择30秒超时。任何客户端断开连接都会导致select返回,您将通过读取集知道哪些是select。您需要做的另一件事是跟踪您在选择中被阻止的时间,以确定何时在30秒标记上进行写入(将下一次选择的超时设置为增量)

    大编辑:与Myn交谈后,提供完整示例:

    public static void main(String[] args) throws IOException {
    
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(4444);
        } catch (IOException e) {
            System.err.println("Could not listen on port: 4444.");
            System.exit(1);
        }
    
        Socket clientSocket = null;
        try {
            clientSocket = serverSocket.accept();
        } catch (IOException e) {
            System.err.println("Accept failed.");
            System.exit(1);
        }
    
        // Set a 1 second timeout on the socket
        clientSocket.setSoTimeout(1000);
    
        PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
        BufferedReader in = new BufferedReader(
                new InputStreamReader(
                clientSocket.getInputStream()));
    
        long myNextOutputTime = System.currentTimeMillis() + 30000;
    
        String inputLine = null;
        boolean connected = true;
        while (connected)
        {
            try {
                inputLine = in.readLine();
                if (inputLine == null)
                {
                    System.out.println("Client Disconnected!");
                    connected = false;
                }
            }
            catch(java.net.SocketTimeoutException e)
            {
                System.out.println("Timed out trying to read from socket");
            }
    
            if (connected && (System.currentTimeMillis() - myNextOutputTime > 0))
            {
                out.println("My Message to the client");
                myNextOutputTime += 30000;
            }
    
    
        }
    
        out.close();
        in.close();
        clientSocket.close();
        serverSocket.close();
    }
    

    这里值得注意的是PrintWriter确实使您远离实际的套接字,而且您不会在写入时捕获套接字断开连接(它永远不会引发异常,您必须手动使用checkError()检查它),您可以改为使用BufferedWriter(需要使用flush()来推送输出),并像BufferedReader一样处理它以捕获写入时的disco