Socket 长连接

最近再做根据 Cmpp 协议对接一个短信网关接口。
考虑到需要频繁的与网关服务器进行数据交互,因此使用长连接。

如何区分长连接,短连接 ?

所谓短连接就是建立一次tcp握手成功后进行数据交互,交互完成主动或者关闭tcp。 主动关闭 一般就是关闭socket或者关闭socket的 in ou流。被动关闭会受限操作系统的配置。比如建立tcp成功之后的一段时间若无数据交互,则操作系统会主动关闭这次tcp连接。

长连接,其实就是就是在建立一次tcp成功之后,通过一定的心跳机制来保证tcp链路一直建立而不释放。具体的长连接也需要Server的支持。

Java Socket 长连接

  1. 创建一个Socket
    1
    2
    3
    4
    5
    Socket msgSocket = new Socket();
    SocketAddress socAddress = new InetSocketAddress(msgConfig.getIsmgIp(), msgConfig.getIsmgPort());
    SocketAddress locAddress = new InetSocketAddress(InetAddress.getLocalHost(), msgConfig.getIsLocalPort());
    msgSocket.bind(locAddress);
    msgSocket.connect(socAddress, SOCKET_TIME_OUT);

创建客户端socket 有多种方式,最常用的方式为Socket msgSocket = new Socket(msgConfig.getIsmgIp(), msgConfig.getIsmgPort(), InetAddress.getLocalHost(), msgConfig.getIsLocalPort());,但通过这个方式我发现 Socket 会自动关闭。 后来尝试使用上面的方法创建一个Socket 并通过 connect 设置超时时间,然后在超时时间内进行一次心跳交互,可以达到http长连接。

如何判断是否为长连接

若http协议可以根据http head 中的 keep-alive 判断是否为长连接。
对于tcp或者socket,我们再与服务器建立长连接时会开辟一个端口,数据会通过这个端口与服务器进行数据交互,因此我们可以监控这个端口,查看这个端口的状态。

1
2
3
lsof -i: port

java 2240 root 154u IPv4 205709 0t0 TCP xxx:port-> remote_ip:remote_ip (ESTABLISHED)

TCP 端口说明

TCP 协议规定,对于已经建立的连接,网络双方要进行四次握手才能断开成功,如果缺少了其中某个步骤,将会使连接处于假死状态,连接本身占用的资源也不会被释放。CLOSE_WAIT 和 TIME_WAIT 这两个TCP状态值得我们关注一下

  1. LISTENING 状态
    FTP 服务启动后会处于侦听(LISTENING) 状态

  2. ESTABLISTENED 状态
    ESTABLISTENED的意思是建立连接,表示两台机器正在通信

  3. CLOSE_WAIT
    对方主动关闭连接或者网络异常导致连接中断,这是我方的状态会变成CLOSE_WAIT,此时我方要调用 close() 来使得连接正确关闭。

  4. TIME_WAIT
    我方主动调用 close() 断开连接,收到对方确认后状态会变为 TIME_WAIT。TCP 协议规定TIME_WAIT状态会一直持续2MSL(即两倍的分段最大生存期),以此来确保旧的连接状态不会对新连接产生影响。处于TIME_WAIT 状态的连接占用资源不会被内存释放,所以作为服务器,再可能的情下,尽量不要主动断开连接,减少TIME_WAIT状态造成的资源浪费。

  5. SYN_SENT 状态
    SYN_SENT 状态表示请求连接,当你要访问其他的计算机的服务时首先要发个同步信号给该端口,此时的状态为SYN_SENT,如果连接成功了就变成 ESTABLISTENED,此时SYN_SENT状态非常短暂。

根据TCP协议定义的3次握手断开连接规定,发起socket主动关闭的一方 socket将进入TIME_WAIT状态,TIME_WAIT状态将持续2个MSL(Max Segment Lifetime),在Windows下默认为4分钟,即240秒,TIME_WAIT状态下的socket不能被回收使用. 具体现象是对于一个处理大量短连接的服务器,如果是由服务器主动关闭客户端的连接,将导致服务器端存在大量的处于TIME_WAIT状态的socket, 甚至比处于Established状态下的socket多的多,严重影响服务器的处理能力,甚至耗尽可用的socket,停止服务. TIME_WAIT是TCP协议用以保证被重新分配的socket不会受到之前残留的延迟重发报文影响的机制,是必要的逻辑保证.

常用tcp命令

1
2
3
netstat 

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'