- 网络编程
在讲网络编程之前,首先要了解下网络的架构。
我们都知道TCP/IP网络模型共有7层:
第一层网络接口层:将osi的物理层和数据链路层合二为一。物理层 是网络的传输介质层,处于网络的最低层,是网络的载体。利用物理介质对上次网络提供物理连接。常用的设备哟网卡、集线器、中继器、调制解调器、网线等。数据链路层:在这层,将数据进行分帧,并进行流的控制,屏蔽物理层,为上层(网络层)提供数据链路的连接。本层进行硬件寻址(MAC地址,ARP协议)。
第三层网络层:本层通过寻址来建立两个节点之间的连接,为上层(运输层)提供链路传输功能。负责建立和维护连接,拥塞控制等。(IP协议)
第四层传输层:面向连接和无连接的传输。(tcp,udp,端口)
第五层应用层:不多说
两个在不同网络的主机程序进程进行通信的流程为:
S(Server):传输层打开一个端口,绑定socket套接字,进行监听端口,等待外部的连接。
如果外部有连接,则Accept,
A(client):先建立一个socket套接字,连接到服务器
- 设置TIME_WAIT的原因
可靠地实现TCP全双工连接的终止
TCP协议在关闭连接的四次握手过程中,最终的ACK是由主动关闭连接的一端(后面统称A端)发出的,如果这个ACK丢失,对方(后面统称B端)将重发出最终的FIN,因此A端必须维护状态信息(TIME_WAIT)允许它重发最终的ACK。如果A端不维持TIME_WAIT状态,而是处于CLOSED 状态,那么A端将响应RST分节,B端收到后将此分节解释成一个错误(在java中会抛出connection reset的SocketException)。
因而,要实现TCP全双工连接的正常终止,必须处理终止过程中四个分节任何一个分节的丢失情况,主动关闭连接的A端必须维持TIME_WAIT状态
允许老的重复分节在网络中消逝
TCP分节可能由于路由器异常而“迷途“,在迷途期间,TCP发送端可能因确认超时而重发这个分节,迷途的分节在路由器修复后也会被送到最终目的地,这个迟到的迷途分节到达时可能会引起问题。在关闭“前一个连接”之后,马上又重新建立起一个相同的IP和端口之间的“新连接”,“前一个连接”的迷途重复分组在“前一个连接”终止后到达,而被“新连接”收到了。为了避免这个情况,TCP协议不允许处于TIME_WAIT状态的连接启动一个新的可用连接,因为TIME_WAIT状态持续2MSL,就可以保证当成功建立一个新TCP连接的时候,来自旧连接重复分组已经在网络中消逝。
- 并发服务器
pid_t pid;
int listenfd,connfd;
listenfd = socket(...);
bind(listenfd...);
listen(listenfd,LISTENQ);
for( ; ; ){
connfd = accept(listenfd,...);
if( (pid = Fork()) == 0){
close(listenfd); // child closes listening socket
doit(connfd); // process the request
close(connfd); // done with this client
exit(0);
}
close(connfd); // parent closes connected socket
}
针对一个TCP套接字调用close会导致发送一个FIN,随后是正常的TCP连接终止序列。但是在上面福进程首先调用close(connfd),会什么没有终止连接呢。
我们必须知道每个文件或者套接字都有一个引用计数。引用计数在文件表象中维护着。在创建listenfd的时候,引用计数为1,当复制到子进程的时候,引用计数为2,这么一来,当父进程关闭connfd的时候,他只是把相应的引用计数减为1.该套接字的真正清理应该等引用计数变为0才会发生。