检查Java TCP服务器上的客户端断开连接-仅输出 [英] Checking for a client disconnect on a Java TCP server - output only

查看:92
本文介绍了检查Java TCP服务器上的客户端断开连接-仅输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a Java TCP server which, when a client connects to it, outputs a message to the client every 30 seconds. It is a strict requirement that the client does not send any messages to the server, and that the server does not send any data other than the 30-second interval messages to the client.

当我断开客户端连接时,服务器将在下次尝试写入客户端时才意识到这一点.因此,服务器最多可能需要30秒才能识别出断开连接.

When I disconnect the client, the server will not realise this until the next time it tries to write to the client. So it can take up to 30 seconds for the server to recognise the disconnect.

我想做的是每隔几秒钟检查一次断开连接而不必等待,但是鉴于a)服务器未从客户端接收到消息,b)服务器无法发送任何消息,因此我不确定如何执行此操作其他数据.任何人都可以对此有所了解吗?谢谢.

What I want to do is check for the disconnect every few seconds without having to wait, but I am not sure how to do this given that a) the server does not receive from the client and b) the server cannot send any other data. Would anyone please be able to shed some light on this? Thanks.

推荐答案

即使您的服务器未从客户端接收",客户端套接字上的非阻塞读取也将告诉您,没有任何内容可读取(如您所料),或者客户端已断开连接.

Even though your server doesn't "receive" from the client, a non-blocking read on the client socket will tell you that either there's nothing to be read (as you expect), or that the client has disconnected.

如果您使用的是NIO,则可以简单地使用无阻塞的 Selector 循环(具有无阻塞的套接字),只写30秒的标记.如果 SelectionKey 是可读的,并且 SocketChannel 上的读取返回-1,则说明客户端已断开连接.

If you're using NIO you can simply use a non-blocking Selector loop (with non-blocking sockets) and only write on your 30 second marks. If a SelectionKey is readable and the read on the SocketChannel returns -1 you know the client has disconnected.

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

Another approach with blocking is simply to select with a 30 second timeout. Any client disconnects will cause the select to return and you'll know which ones those are via the read set. The additional thing you'd need to do there is track how long you were blocked in the select to figure out when to do your writes on the 30 second mark (Setting the timeout for the next select to the delta).

在与下面的Myn交谈后,提供了完整的示例:

Big After talking to Myn below, offering complete example:

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 一样处理它,以在写入时捕获迪斯科.

Worth noting here is that the PrintWriter really moves you far away from the actual socket, and you're not going to catch the socket disconnect on the write (It will never throw an exception, you have to manually check it with checkError()) You could change to using a BufferedWriter instead (requires using flush() to push the output) and handling it like the BufferedReader to catch a disco on the write.

这篇关于检查Java TCP服务器上的客户端断开连接-仅输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆