1、主动发起连接状态转换
新建几个client进程,使用下面代码
netstat -apn | grep client
查看6666端口,server
2、主动断开连接状态转换
3、被动接收连接状态转换
4、被动断开连接状态转换
5、2MSL时长
设计在主动关闭方
为什么会有2MSL时长?
(1)让4次握手关闭流程更加可靠;4次握手的最后一个ACK是是由主动关闭方发送出去的,若这个ACK丢失,被动关闭方会再次发一个FIN过来。若主动关闭方能够保持一个2MSL的TIME_WAIT状态,则有更大的机会让丢失的ACK被再次发送出去。
(2)防止lost duplicate对后续新建正常链接的传输造成破坏。lost uplicate在实际的网络中非常常见,经常是由于路由器产生故障,路径无法收敛,导致一个packet在路由器A,B,C之间做类似死循环的跳转。IP头部有个TTL,限制了一个包在网络中的最大跳数,因此这个包有两种命运,要么最后TTL变为0,在网络中消失;要么TTL在变为0之前路由器路径收敛,它凭借剩余的TTL跳数终于到达目的地。但非常可惜的是TCP通过超时重传机制在早些时候发送了一个跟它一模一样的包,并先于它达到了目的地,因此它的命运也就注定被TCP协议栈抛弃。
6、端口复用函数
server的TCP连接没有完全断开之前是不允许重新监听
TCP连接没有完全断开指的是(127.0.0.1:6666)没有完全断开,而我们重新监听的是lis-tenfd(0.0.0.0:6666),虽然是占用同一个端口,但IP地址不同,(127.0.0.1:6666)对应的是与某个客户端通讯的一个具体的IP地址,而(0.0.0.0:6666)对应的是wildcard address。
解决这个问题的方法是使用setsockopt()设置socket描述符的选项SO_REUSEADDR为1,表示允许创建端口号相同但IP地址不同的多个socket描述符。
在server代码的socket()和bind()调用之间插入如下代码:
int opt = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
7、半关闭的两个函数
通信双方,只有一端关闭通信-----FIN_WAIT_2
有两种方式关闭
1、close(fd);
2、shutdown(int fd,int how); 关闭fd的某个缓冲区
how: SHUT_RD 关读端
SHUT_WR 关写端
SHUT_RDWR 关读写
注意:
- 如果有多个进程共享一个套接字,close每被调用一次,计数减1,直到计数为0时,也就是所用进程都调用了close,套接字将被释放。
- 在多进程中如果一个进程调用了shutdown(sfd, SHUT_RDWR)后,其它的进程将无法进行通信。但,如果一个进程close(sfd)将不会影响到其它进程。