UDP端口未打开,sendto()失败后,recvfrom设置无效,直接返回错误码?

本文介绍了一种检测UDP连接是否正常的方法。通过定时发送数据包并使用WSAGetLastError()判断错误号是否为10054,可以有效检测UDP是否打开。文章详细解释了recvfrom函数返回0的情况,并提供了具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

在项目中需要检测UDP是否打开,刚开始实现是定时发送数据包,recvfrom设置超时时间是1s。结果发现当UDP没有开启时(比如电脑开机后直接运行)recvfrom设置的超时时间无效,而是立即返回SOCKET_ERROR,recvfrom函数返回0。

recvfrom返回值为0有两种情况:
1.socket已经"温和"关闭(使用shutdown或者设置linear属性)
2.对方发送一个空数据,也就是对方发送的数据长度为0。这时socket也就可以接收到的,并且recvfrom返回值为0。

只有服务端的recvfrom接收的是所有外部发向这个端口号的信息的,客户端的recvfrom是根据socket里的信息来收的,是绑定过服务器IP和端口号的。


最后解决方法: 定时发送数据包,用WSAGetLastError()判断错误号是否是10054。

调用WSAGetLastError()返回的结果为0,GetLastError()也是返回0。原因:int err=WSAGetLastError();的调用必须放到其他系统函数调用之前,也就是说,出现错误后,第一时间存储WSAGetLastError结果,而不能调用其他函数之后再调用此函数。因为调用系统函数会清除WSAGetLastError,致使结果返回0.
 

代码:

	int TimeOut = 1000;
    //设置接受等待时间为TimeOut
	if(setsockopt(g_sock,SOL_SOCKET,SO_RCVTIMEO,(char *)&TimeOut,sizeof(TimeOut))==SOCKET_ERROR){
		return -1;
	}

	for(i=0; i<5; i++){
		memset(szBuff, 0, sizeof(szBuff));
		strcpy(szBuff,"Test the UDP connect!\r\n");
		ret = sendto(g_sock,szBuff,strlen(szBuff),0,(sockaddr *)&addrSend,sizeof(addrSend));
		printf("%d send data: %s to %s:%d \n",ret,szBuff,inet_ntoa(addrSend.sin_addr),ntohs(addrSend.sin_port));
		int nRecLen = sizeof(addrSend);
		//等待并接受来自B的数据
		memset(szBuff, 0, sizeof(szBuff));
		ret = recvfrom(g_sock,szBuff,256,0,(sockaddr *)&addrSend,&nRecLen);
		if(GetLastError() == 10054){
			Sleep(1000);
		}
		printf("ret  %d data: %s to %s:%d \n",ret, szBuff,inet_ntoa(addrSend.sin_addr),ntohs(addrSend.sin_port));
		if (ret > 0  && strcmp(szBuff, "The Battery board is working!\r\n")==0) {
			connectBoard = true;
			break;
		}
	}

参考:

https://bbs.youkuaiyun.com/topics/391937100

https://blog.youkuaiyun.com/tianbaowen/article/details/8485567

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值