Java服务端如何感知客户端断链

我的问题有两个:
1.java服务器端如何感知客户端断链
2.一个Server支持多个客户端连接时最优实现
说明:
针对问题一:出现的问题是,下面的代码中当客户端断链后,while(true)一直死循环导致输出一直为null
针对问题二:我现在的实现是,每来一个客户端连接,便开启一个线程去处理,感觉不是合理的处理方式,因为当成千上万个客户端去连接时,这样去创建进程根本不可能,求最优的解决方法。

希望各位码友不吝赐教,谢谢~~~
Java 服务器端代码如下,实现功能为起一个服务器端,其他客户端来连接,根据客户端发送的消息直接输出:

package MyTCP;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.channels.NonWritableChannelException;

public class Server
{
    public static void main(String[] args)
    {
        
        StartListen();
    }
    
    /**
     * 设置监听的端口号
     */
    public static void StartListen()
    {
        int port = 10001;
        createTCP(port);
    }
    
    /**
     * 
     * @param port
     * @param address
     */
    public static void createTCP(int port)
    {
        try
        {
            ServerSocket serverSocket = new ServerSocket(port);
            System.out.println("server list on 127.0.0.1:10001");
            
            while (true)
            {
                Socket socket = serverSocket.accept();
                new Thread(new ChildThred(socket)).start();
            }
        } 
        catch (IOException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

class ChildThred implements Runnable
{
    BufferedReader bufrea = null;
    Socket socket = null;
    public ChildThred(Socket socket)
    {
        this.socket = socket;
    }

    @Override
    public void run()
    {
        try
        {
            bufrea = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            
            while(true)
            {    
                System.out.println("服务器端收到的客户端的消息为 : " + bufrea.readLine());    
            }
            
        }
        catch (Exception e)
        {
            // TODO: handle exception
            e.printStackTrace();
        }
        finally 
        {
            try
            {
                bufrea.close();
                socket.close();
            }
            catch (Exception e) 
            {
                System.out.println(e.getMessage());
            }
        }
    }
}
阅读 4.5k
2 个回答
  • 对于第一个问题,题主参考下这篇文章,客户端断链分为正常情况和异常情况,题主说一直死循环,是因为客户端关闭发送通道,服务端读取不到数据了,你的程序应该在读取数据的时候判断一下,读到null就应该跳出循环,把需要发送的数据发送出去,再关闭通道。这是正常的情况,异常的情况又分为两种,一种是客户端程序崩溃或异常退出,服务端在read时会抛出connection reset by peer异常,这时只需要捕获异常关闭通道就行了。还有一种情况是网络中断或者客户端断电,这个时候就需要心跳机制了。
  • 对于第二个问题,那就复杂了,题主用的是阻塞模型(BIO),可以参考一下Tomcat(BIO模型已过时)的处理机制。

clipboard.png

Tomcat先用LimitLatch做一层限流,连接到来时将Socket封装成任务丢到线程池的任务队列,而不是立马创建线程,这样做利用了任务队列起到了缓冲作用,但是由于IO模型,这种方式还是不能充分利用服务端资源,因为线程在等待IO时阻塞了,在阻塞期间线程不能做任何其他事情,这样造成线程资源浪费。

阻塞模型在高并发下自然不是最好的选择,多路复用才是最好的选择,而且相当成熟。题主可以先了解下五大IO模型,再回来看待这第二个问题。

  • 问题一: 检测用户存活一般是用到心跳机制
  • 问题二: 每个用户连接都是会新开线程的,只是在大规模下的服务器,会采用负载均衡搭建服务器集群,使得用户错误感知服务器只有一个,但是在均衡后的其实是服务器集群,每个服务器只负责自己能力内的用户数(也就是线程数)。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏