UDP发送Select不正确返回的解决办法

http://www.vchelp.net/cndevforum/subject_view.asp?subject_id=115415


proxywin
方向
发表于 2004-10-22 18:12:42 [50分] 已经接受正确答案 给会员proxywin留言 显示可打印的文本

在UDP套接字上调用sendto发送数据报给接收端,很奇怪,如果对端机器没有启动,这个sendto就被阻塞很长时间,然后才返回发送成功.一旦对端启动,sendto很快返回了.
为什么UDP发送数据还会出现这种情况,它不是无连接的吗?要命的是后面有很多数据报要发给别人,全给它堵在这个地方了.也就是说,对方可以让我的服务器烂掉.
请教.

proxywin
方向
第1楼 回复于2004-10-22 18:54:22 给会员proxywin留言

这个论坛是完了

proxywin
方向
第2楼 回复于2004-10-22 18:55:08 给会员proxywin留言

自己顶着玩算了

william_xiong
化十
第3楼 回复于2004-10-22 19:02:53 给会员william_xiong留言

你用的是Select模型吗?
如果你用线程,就不会出现如你说的那种情况。

proxywin
方向
第4楼 回复于2004-10-22 19:37:15 给会员proxywin留言

谢谢化石.总算有抱义的.
我是用线程和select函数的,select马上成功,但是就是发不出去,因为对端没有起来.起来之后就可以了.就奇怪UDP为什么会这样,它一个劲发就行了,难道还搞停等不成?
而且用
setsockopt(m_hSocket,SOL_SOCKET,SO_SNDTIMEO,(char*)&TimeOut,sizeof(TimeOut));
设置sendto的最大阻塞时间也不能成功,虽然函数返回0,但getsockopt得到的最大阻塞时间
永远都是4秒.
也就是说,若对端没起来,这个线程每发一个数据报,就要被阻塞4秒,后续的发给别人的数据报全被堵住了.我总不能每个客户都起一个线程.
请教

william_xiong
化十
第5楼 回复于2004-10-22 19:59:49 给会员william_xiong留言

是这样的,如果你的Winsock是Winsock2以前的版本,你可以直接调用WSACancelBlockingCall()来取消正在执行的阴塞调用。或通过ioctlsocket()设置套接口工作方式,

如果为Winsock2.0,则可以通过WSAIoctl()来设置套接口的工作方式,即设置为非阻Sai模式,

注:如果使用WSAAsynSelect()或WSAEventSelect()函数,则套接口将会自动设置为非阻Sai模式。

proxywin
方向
第6楼 回复于2004-10-22 20:38:35 给会员proxywin留言

感谢化石!设为非阻塞可以解决问题了.

但根子还没解决,再请教UDP的怪现状如何办:

在服务器端还没有起来的时候,客户端在UDP套接字上调用sendto向它发送了许多UDP数据报.结果,
由于对端不可达,使得客户端UDP套接字状态异常:对它select会发现套接字可读,但recvfrom后返回-1,错误代码为10054,即连接被复位.而且,sendtoN次不可达的UDP报文,该套接字就会使得N次出现这种假可读,要调用recvfrom才能跳过这些假可读.当时迷惑为什么UDP知道对方不可达的,虫虫老兄告诉说是
反馈的ICMP报文导致UDP套接字异常的.
   我的问题是,如何跳过这N次select假可读?如果前面发送了大量的不可达数据报时,要是循环利用select和recvfrom去跳过效率太低了,而且还会导致客户端启动很长一段时间内返回的真实数据报丢失.
   或者, 如何禁止ICMP修改我的UDP套接字状态?
   或者,如何在对端禁止ICMP回应?我指的是程序实现.
谢谢

william_xiong
化十
第7楼 回复于2004-10-22 21:41:09 给会员william_xiong留言
本回复被接受本回复被接受作为正确答案


首先,如果在底层处理这种问题,完全没有必要,因为这种问题完全可以在程序设计中避免,
给你一个供参考的方案,
客户端在启动后一般都有登录操作,如果登录成功,服务器会把在线用户发给客户端,如果没有此项,至少还应让服务器返回一个登录成功的ACK,

如果ACK成功,则发送数据,否则,则视为对方不可达,则不用发送数据,

proxywin
方向
第8楼 回复于2004-10-23 8:00:47 给会员proxywin留言

  是这样,客户登陆检查可以做成你说的那种机制,然而一旦开始向客户发送UDP数据报,服务器就无法识别这个客户的通断了:假如这个客户断连了1秒钟,又恢复了.那么服务器端UDP套接字由于sendto了一秒的不可达数据报,导致套接字处于异常的可读状态,而且这些可读状态积压了N个(等于1秒内发送的数据报个数).
  因为我实现了一个心跳检测机制,由于这种UDP套接字异常,我再也无法读取到客户端反馈回来HELLO ACK了,只有认为客户断连.这是很不合理的.(除非使用一个循环不断取读取UDP套接字直到其不可读,这可以在短时间内跳过这些异常,但如果在断连的几秒内发送了巨多的数据报,那这个循环次数是巨大的,等于sendto的次数,这样会严重影响效率)
化石老兄有何高见?

william_xiong
化十
第9楼 回复于2004-10-23 23:33:01 给会员william_xiong留言

呵呵,事实上sendto(...)的返回值如果与Buf的Size大小相同,可视为发送成功,否则,则视为对方不可达,然后用WSAGetLastError()来得到错误信息,你用这个return value先试一下,
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值