最近再做根据 Cmpp 协议对接一个短信网关接口。
考虑到需要频繁的与网关服务器进行数据交互,因此使用长连接。
如何区分长连接,短连接 ?
所谓短连接就是建立一次tcp握手成功后进行数据交互,交互完成主动或者关闭tcp。 主动关闭 一般就是关闭socket或者关闭socket的 in ou流。被动关闭会受限操作系统的配置。比如建立tcp成功之后的一段时间若无数据交互,则操作系统会主动关闭这次tcp连接。
长连接,其实就是就是在建立一次tcp成功之后,通过一定的心跳机制来保证tcp链路一直建立而不释放。具体的长连接也需要Server的支持。
Java Socket 长连接
- 创建一个Socket创建客户端socket 有多种方式,最常用的方式为
1
2
3
4
5Socket 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 msgSocket = new Socket(msgConfig.getIsmgIp(), msgConfig.getIsmgPort(), InetAddress.getLocalHost(), msgConfig.getIsLocalPort());
,但通过这个方式我发现 Socket 会自动关闭。 后来尝试使用上面的方法创建一个Socket 并通过 connect 设置超时时间,然后在超时时间内进行一次心跳交互,可以达到http长连接。
如何判断是否为长连接
若http协议可以根据http head 中的 keep-alive 判断是否为长连接。
对于tcp或者socket,我们再与服务器建立长连接时会开辟一个端口,数据会通过这个端口与服务器进行数据交互,因此我们可以监控这个端口,查看这个端口的状态。
1 | lsof -i: port |
TCP 端口说明
TCP 协议规定,对于已经建立的连接,网络双方要进行四次握手才能断开成功,如果缺少了其中某个步骤,将会使连接处于假死状态,连接本身占用的资源也不会被释放。**CLOSE_WAIT 和 TIME_WAIT ** 这两个TCP状态值得我们关注一下
LISTENING 状态
FTP 服务启动后会处于侦听(LISTENING) 状态ESTABLISTENED 状态
ESTABLISTENED的意思是建立连接,表示两台机器正在通信CLOSE_WAIT
对方主动关闭连接或者网络异常导致连接中断,这是我方的状态会变成CLOSE_WAIT,此时我方要调用 close() 来使得连接正确关闭。TIME_WAIT
我方主动调用 close() 断开连接,收到对方确认后状态会变为 TIME_WAIT。TCP 协议规定TIME_WAIT状态会一直持续2MSL(即两倍的分段最大生存期),以此来确保旧的连接状态不会对新连接产生影响。处于TIME_WAIT 状态的连接占用资源不会被内存释放,所以作为服务器,再可能的情下,尽量不要主动断开连接,减少TIME_WAIT状态造成的资源浪费。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 | netstat |