server端:
client 端:
一个server在和两个client聊天~~~
步骤:server端 1)调用socket(),创建套接字,返回值是文件描述符。
2)调用bind(),绑定ip和端口号。
3)调用listen(),监听等待连接状态的客户端。
4)调用accept(),接受连接,如果没有客户端连接,就以阻塞方式等待,返回值是文件描述符,注意accept拿到的是已经三次握手之后的连接。
5)读写数据,因为tcp提供的是全双工的通信,所以既可以读,也可以写。
client端 1)调用connect(),主动请求连接
2)读写数据。
因为客户端不需要固定的端口号,因此不必调用bind(),客户端的端口号由内核自动分配。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
终止这两个进程的时候,如果先终止server端,后终止client端,之后立即启动server端,会出现这种情况:
地址已经被使用。
但是过几分钟,再启动server,就不会有这样的问题,或者先终止client端,后终止server端,也不会有这样的问题。
TCP协议规定,主动关闭连接的一方要处于TIME_WAIT状态,等待两个MSL(maximum segment lifetime)的时间后才能回到CLOSED状态,而被动关闭的一方则直接转CLOSE状态。
当一个socket关闭的时候,是通过两端互发信息的四次挥手过程完成的。所以必须完全正确的传输四次握手的四个节,不能有任何的丢失。
但是1)没有任何机制保证最后的一个ACK能够正常传输到网络上2)网络上可能有残余的数据包(wandering duplicates),我们也必须能够正常处理。
TIME_WAIT就是为了解决这两个问题而生的。
1)假设最后一个ACK丢失了,被动关闭一方会重发它的FIN。所以主动关闭一方必须维持一个有效状态信息(TIMEWAIT状态下维持),以便能够重发ACK。
2)假设目前连接的通信双方都已经调用了close(),双方同时进入CLOSED的终结状态,而没有走TIME_WAIT状态。会出现如下问题,现在有一个新的连接被建立起来,使用的IP地址与端口与先前的完全相同,后建立的连接是原先连接的一个完全复用。还假定原先的连接中有数据报残存于网络之中,这样新的连接收到的数据报中有可能是先前连接的数据报。为了防止这一点,TCP不允许新连接复用TIME_WAIT状态下的socket。处于TIME_WAIT状态的socket在等待两倍的MSL时间以后,将会转变为CLOSED状态。这就意味着,一个成功建立的连接,必然使得先前网络中残余的数据报都丢失了。
MSL是一个数据报在网络上单向发出到确认丢失的时间,一个数据报有可能在发送过程中或是响应过程中成为残余数据报,所以需要两倍的MSL
虽然TIME_WAIT对我们是有利的,但有时候我们也希望避免等待的情况,让服务器可以马上跑起来。
解决方法:在socket()和bind()调用之间插入如下代码:
int opt = 1;
setsockopt(listen_sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));