1、在客户端服务器模式中,如果服务器退出,然后立即重新启动的话,然后就出现”试图绑定一个已经在使用的端口”的错误,要等过一段时间之后才可以bind,这是为什么呢??? 或许你感到非常迷惑,明明服务器的套接字已经被关闭了,但为什么仍然禁止绑定端口。这是由于套接字处于TIME_WAIT状态引起的,这个状态会持续2MSL时间。在TIME_WAIT退出后,套接字被删除,该地址才能被重新绑定而不出现问题。 如图:
2、等待TIME_WAIT真的让人很不爽,可以采用下面这种方式避免TIME_WAIT状态。 在bind之前,用SO_REUSEADDR选项调用setsockopt函数。
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); 1 1功能:用于在任意类型、任意状态的套接字上设置选项值。选项影响套接字的操作。 参数: sockfd:套接字的描述符。 level:选项定义的层次。
SOL_SOCKET: 基本套接口 IPPROTO_IP: IPv4套接口 IPPROTO_IPV6: IPv6套接口 IPPROTO_TCP: TCP套接口
optname:设置的选项。 optval:指向选项类型的指针。选项有两种类型的 ,一种是布尔类型的选项,表示允许(TRUE)或禁止(FALSE)一种特性。另一种整形选项,非零表示允许,零表示禁止。 optlen:optval缓冲区去的大小。 返回值:若无错误发生,则返回0。
选项 类型 意义 SO_BROADCAST BOOL 允许套接口传送广播信息。 SO_DEBUG BOOL 记录调试信息。 SO_DONTLINER BOOL 不要因为数据未发送就阻塞关闭操作。设置本选项相当于将SO_LINGER的l_onoff元素置为零。 SO_DONTROUTE BOOL 禁止选径;直接传送。 SO_KEEPALIVE BOOL 发送“保持活动”包。 SO_LINGER struct linger FAR* 如关闭时有未发送数据,则逗留。 SO_OOBINLINE BOOL 在常规数据流中接收带外数据。 SO_RCVBUF int 为接收确定缓冲区大小。 SO_REUSEADDR BOOL 允许套接口和一个已在使用中的地址捆绑(参见bind())。 SO_SNDBUF int 指定发送缓冲区大小。 TCP_NODELAY BOOL 禁止发送合并的Nagle算法。 setsockopt()不支持的BSD选项有:
选项名 类型 意义 SO_ACCEPTCONN BOOL 套接口在监听。 SO_ERROR int 获取错误状态并清除。 SO_RCVLOWAT int 接收低级水印。 SO_RCVTIMEO int 接收超时。 SO_SNDLOWAT int 发送低级水印。 SO_SNDTIMEO int 发送超时。 SO_TYPE int 套接口类型。 IP_OPTIONS 在IP头中设置选项。
用法示例:
1.设置调用closesocket()后,仍可继续重用该socket。调用closesocket()一般不会立即关闭socket,而经历TIME_WAIT的过程。 BOOL bReuseaddr = TRUE; setsockopt( s, SOL_SOCKET, SO_REUSEADDR, ( const char* )&bReuseaddr, sizeof( BOOL ) ); 2.在send(),recv()过程中有时由于网络状况等原因,收发不能预期进行,可以设置收发时限: int nNetTimeout = 1000; //1秒 //发送时限 setsockopt( socket, SOL_SOCKET, SO_SNDTIMEO, ( char * )&nNetTimeout, sizeof( int ) ); //接收时限 setsockopt( socket, SOL_SOCKET, SO_RCVTIMEO, ( char * )&nNetTimeout, sizeof( int ) );