C语言socket服务端报错:bind socket error: Address already in use(errno: 98)(setsockopt()各使用场景)

Posted Dontla

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言socket服务端报错:bind socket error: Address already in use(errno: 98)(setsockopt()各使用场景)相关的知识,希望对你有一定的参考价值。

文章目录

问题

客户端没关,把服务端关了,然后再启动服务端,就报这个错误了

验证:先关服务端,再关客户端,再开启服务端,开始的时候就报下面错误


但是过了一段时间(大约几十秒?),再启动服务端又好了

原因

猜测是服务端这边的问题,当用ctrl+c结束服务端程序时,没有close一开始服务端socket函数返回的listenfd(猜测这个listenfd是被注册在linux系统下,即使服务端和客户端关掉,它还在,要过一段时间才释放)

验证结果

ctrl+c的时候只close connfd,还是老样子

ctrl+c的时候只close listenfd,可以了,看来就是listenfd没释放导致的

ctrl+c的时候先close connfd,再close listenfd,又报bind socket error: Address already in use(errno: 98)了,,,

两台虚拟机测试,看是服务端问题还是客户端问题

先放一放吧,LY说先不用管服务端,关注我自己客户端就好了

参考文章:解决socket.error: [Errno 98] Address already in use问题

参考文章:操作socket报Too many open files errno :24错误解决方法

20220401 关闭了listen_fd还不行

问题原因

这是因为在TCP/IP终止连接的四次握手中,当最后的ACK回复发出后,有个2MSL的时间等待,MSL指一个片段在网络中最大的存活时间,这个时间一般是30秒,所以基本上过60秒后就可以重新连接!
为什么要等待2MSL?是因为在最后发出ACK回复后,发送方不能确认ACK是否被另一端正常收到,如果另一端没有收到ACK回复的话,将会在1MSL后再次发送FIN片段。所以说发送方等待2MSL时间,也就是刚好它发ACK回复和对方发送FIN片段的时间,如果此时间内都没有再次收到FIN片段的话,发送方就假设对方已经正常接收到了ACK回复,此时它就会正常关闭连接!

参考文章:Python socket.error: [Errno 98] Address already in use的原因和解决方法

因为即使关闭了fd,地址仍然在通信,当超时后,才会自动释放,这篇文章讲了直接修改内核配置来讲超时时间设置小的方法(但这种方法不是在程序里实现的,不是我们需要的)

解决socket.error: [Errno 98] Address already in use问题
用vi打开配置文件:

# vi  /etc/sysctl.conf 

然后,在这个文件中,加入下面的几行内容:

net.ipv4.tcp_syncookies = 1    # 这一行配置文件里如果有就不用添加了  
net.ipv4.tcp_tw_reuse = 1  
net.ipv4.tcp_tw_recycle = 1  
net.ipv4.tcp_fin_timeout = 5 

最后输入下面的命令,让内核参数生效:

# /sbin/sysctl -p  

找到一个socket shutdown函数不知道有没有用

测了还是没有用。。。
参考文章:Socket之shutdown()用法

20220512 在新的多连接cpp socket server上也遇到了相同的问题 bind error

可以看到我们book250 socket server建立了三个连接(三个子进程)


然后ctrl + c结束服务端再立即启动就遇到了bind error错误

看了这篇文章:Socket通信bind错误

其实感觉这个问题并不严重哈,只要服务端正常的话,是不会轻易关闭的

但是这里确实提供了一些特殊的使用场景:

应用举例

  1. 设置调用close(socket)后,仍可继续重用该socket。调用close(socket)一般不会立即关闭socket,而经历TIME_WAIT的过程。
BOOL bReuseaddr = TRUE;
setsockopt( s, SOL_SOCKET, SO_REUSEADDR, ( const char* )&bReuseaddr, sizeof( BOOL ) );
  1. 如果要已经处于连接状态的soket在调用closesocket()后强制关闭,不经历TIME_WAIT的过程:
BOOL bDontLinger = FALSE;
setsockopt( s, SOL_SOCKET, SO_DONTLINGER, ( const char* )&bDontLinger, sizeof( BOOL ) );
  1. 在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 ) );
  1. 在send()的时候,返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节(异步);系统默认的状态发送和接收一次为8688字节(约为8.5K);在实际的过程中如果发送或是接收的数据量比较大,可以设置socket缓冲区,避免send(),recv()不断的循环收发:
// 接收缓冲区
int nRecvBufLen = 32 * 1024; //设置为32K
setsockopt( s, SOL_SOCKET, SO_RCVBUF, ( const char* )&nRecvBufLen, sizeof( int ) );
//发送缓冲区
int nSendBufLen = 321024; //设置为32K
setsockopt( s, SOL_SOCKET, SO_SNDBUF, ( const char )&nSendBufLen, sizeof( int ) );
  1. 在发送数据的时,不执行由系统缓冲区到socket缓冲区的拷贝,以提高程序的性能:
int nZero = 0;
setsockopt( socket, SOL_SOCKET, SO_SNDBUF, ( char * )&nZero, sizeof( nZero ) );
  1. 在接收数据时,不执行将socket缓冲区的内容拷贝到系统缓冲区:
int nZero = 0;
setsockopt( s, SOL_SOCKET, SO_RCVBUF, ( char * )&nZero, sizeof( int ) );
  1. 一般在发送UDP数据报的时候,希望该socket发送的数据具有广播特性:
BOOL bBroadcast = TRUE;
setsockopt( s, SOL_SOCKET, SO_BROADCAST, ( const char* )&bBroadcast, sizeof( BOOL ) );
  1. 在client连接服务器过程中,如果处于非阻塞模式下的socket在connect()的过程中可以设置connect()延时,直到accpet()被调用(此设置只有在非阻塞的过程中有显著的作用,在阻塞的函数调用中作用不大)
BOOL bConditionalAccept = TRUE;
setsockopt( s, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, ( const char* )&bConditionalAccept, sizeof( BOOL ) );
  1. 如果在发送数据的过程中send()没有完成,还有数据没发送,而调用了close(socket),以前一般采取的措施是shutdown(s,SD_BOTH),但是数据将会丢失。
    某些具体程序要求待未发送完的数据发送出去后再关闭socket,可通过设置让程序满足要求:
struct linger 
u_short l_onoff;
u_short l_linger;
;
struct linger m_sLinger;
m_sLinger.l_onoff = 1; //在调用close(socket)时还有数据未发送完,允许等待
// 若m_sLinger.l_onoff=0;则调用closesocket()后强制关闭
m_sLinger.l_linger = 5; //设置等待时间为5秒
setsockopt( s, SOL_SOCKET, SO_LINGER, (const char*)&m_sLinger, sizeof(struct linger));

以上是关于C语言socket服务端报错:bind socket error: Address already in use(errno: 98)(setsockopt()各使用场景)的主要内容,如果未能解决你的问题,请参考以下文章

python socket编程腾讯云下报错[Errno 99] Cannot assign requested address的解决方式

在C/C++/ObjC编程语言中有没有啥方法获取 socket 是不是连接啊?就像C#中Socke

阿里云服务器配置uwsgi报错bind(): Cannot assign requested address [core/socket.c line 769]

如何连接插座?

windows socket ipv6 SOCK_RAW

Centos7.5启动Apache Web 服务报错AH00072: make_sock: could not bind to address [::]:9096