tcp三次握手和四次挥手状态图:
为什么需要2MSL:
原因1:让四次挥手过程更加可靠,确保最后一个发送给对方的ACK到达;若对方没有收到ACK应答,对方会再次发送FIN请求关闭,此时在2MSL时间内被动关闭方仍然可以发送ACK给对方;
原因2:为了保证在2MSL时间内,不能启用相同的SOCKET_PAIR
问题:
启动服务端和客户端,然后先关闭服务端,又立即启用时会报错:bind error:Adddress already in use;先关闭客户端,又立即启用就不会报错。
端口复用:
解决端口复用的问题:bind error:Adddress already in use,发生在关闭服务端后,又立即启用。
int setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen);
在bind函数之前调用,添加以下代码就可以解决端口复用:
int opt=1;
setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opet,sizeof(int));
SO_REUSEADDR:如果*val为非零,重用bind中的地址。
半关闭状态:
如果一方close,另一方没有close,则认为时半关闭状态,处于半关闭状态的时候,可以接收数据,但是不能发送数据,相当于把缓冲区的写缓冲区操作关闭了。
注意:半关闭一定出现在主动关闭的一方。
int shutdown(int sockfd, int how);
函数参数:
sockfd:监听描述符
how:
If how is SHUT_RD,
further receptions will be disallowed. If how is SHUT_WR, further
transmissions will be disallowed. If how is SHUT_RDWR, further recep‐
tions and transmissions will be disallowed.
shutdown和close的区别:
1 shutdown可以实现半关闭,close不行;
2 shutdown关闭的时候,不考文件描述符的引用计数,是彻底关闭;
close考虑文件描述符的引用计数(创建子进程加一,dup函数也加一),调用一次close只是将引用次数减一,只有减到零才真正关闭。
长连接和短连接:
长连接:连接建立好之后,一直保持连接不关闭
短连接:连接使用完之后就立刻关闭。
心跳包:
心跳包是用于长连接是否正常的字符串;
作用:检查与对方的连接是否正常;
心跳包一般用于长连接。
发送心跳过程:
1 服务A给B发送心跳数据AAAA,服务B收到AAAA之后,给A回复BBBB,此时A收到BBBB之后,认为连接正常。
假如A连续发送多次(3~5)之后,仍然没有收到B的回复,则认为连接异常。
异常之后,A应该重新建立连接:
先close原来的连接,然后在connect连接。
如何让心跳数据和正常的业务数据不混淆:
解决方法:
双方可以协商协议,如四个字节长度+具体数据
如果对方发送心态数据应该:0004AAAA;
如果发送业务数据:0009123456789;
对方收数据的时候,先收4个字节的报头数据,若最后计算长度为4,且数据内容是AAAA,则认为是心跳数据,然后B发送0004BBBB。