select和send的问题

Kernel_Don 2009-01-07 04:24:57
使用select主要是为了避免阻塞,比如对于一个TCP连接,缓冲区满了,再send时就阻塞住了,如果对方由于某种原因一直没有recv的话,send方也就死了。
所以通常可以
if (select(n, NULL, &fs_w, NULL, &tv) > 0)
{
if (FD_ISSET(fd, &fs_w))
send(fd, buf, len);
}

但会不会有这样的情况:缓冲区没充满,但只有少量的空间了,例如只剩下 100 BYTE的空间。这时select返回是可写的,但send(fd,buf, 200),写了200字节,其中100写进去了,另100字节写不进去,被阻塞了。


会不会有这样的情况呢?
...全文
865 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
caitian6 2009-01-08
  • 打赏
  • 举报
回复
关注,期待解决办法
野男孩 2009-01-08
  • 打赏
  • 举报
回复
当然会。send函数的返回值会告诉你发送了多少字节的数据的。

注意,不是说你send发送1000字节,就能发送1000字节成功的。
RuanJianRenAtMSN 2009-01-08
  • 打赏
  • 举报
回复
SELECT 模式是windows通知方式,只有条件成立才会通知你发送或接收,这方面系统已帮你想到了。若数据量比较大可以设置接收发送工作区大些。
Learn-anything 2009-01-08
  • 打赏
  • 举报
回复
kk
Kernel_Don 2009-01-08
  • 打赏
  • 举报
回复
使用非阻塞只是绕过这个问题,但使用非阻塞后,进行下去也可能带出其他问题。
不是使用非阻塞可不可以的问题,使用别的方法当然可以,没有哪个问题是只有唯一解的。比如说花钱请别人来做,只要他帮我实现顺利信通就可,也是一个绕过这个问题的方法啊,那样更轻松。
猞猁狲 2009-01-08
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 cnzdgs 的回复:]
用非阻塞模式,当要阻塞时会返回失败,错误码是WSAEWOULDBLOCK。
[/Quote]
同意
blackcat242 2009-01-08
  • 打赏
  • 举报
回复
使用非阻塞的就可以了
Kernel_Don 2009-01-08
  • 打赏
  • 举报
回复
编了个程序测试了一下,发现不会出现select大于0也使send阻塞这种情况,只要select返回大于0,send就能成功地发送并返回,如果select返回0,再调用send就会阻塞。

在一端循环调用:
if (select(n, NULL, &fs_w, NULL, &tv) > 0)
{
if (FD_ISSET(fd, &fs_w))
len = send(fd, buf, 1024*16+67);
}
每次发一定长度的数据,加67是为了使数据长度不是1024的整数倍

另一端不调用recv

发送的前5次,send都返回了16451(即1024*16+67),当发送端发送了5次后,select返回0,就是说select检测到了缓冲区满了,不能再写入了。
把select去掉,直接send,结果是相同的,发了5次后,第6次send时,在send上阻塞了。

但有点想不通select是怎么知道缓冲区满了不能发送的?我每次发16451个字节,5次就是82255字节,难道这个长度这个长度刚好充满缓冲区?假如第6次我只是要发送1个字节,难道就会使缓冲区溢出了?把每次发送的字节数改为1024*16+71或1024+47等等不同的数值,结果都是发了八十多K时select就开始返回0了。

推测select记录上次发送长度,如果剩余缓冲区小于上次发送长度,则返回0。把测试程序改了一下,不调用select,只调用send,前5次发送82255字节,send返每次都返回82255,第6次只发1个字节,结果send还是阻塞了。此推测不正确:-(。

查了一下TCP的机制,发现TCP是在收发两端以滑动窗口的方式控制的,上面的实验结果应该是send了八十多K后,把发送端的每一个窗口都占用了,所以再send就阻塞了,select应该是检测还有多少空闲的窗口。想通了,呵呵,应该是这样。

sun007700 2009-01-08
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 Kernel_Don 的回复:]
编了个程序测试了一下,发现不会出现select大于0也使send阻塞这种情况,只要select返回大于0,send就能成功地发送并返回,如果select返回0,再调用send就会阻塞。

在一端循环调用:
if (select(n, NULL, &fs_w, NULL, &tv) > 0)
{
if (FD_ISSET(fd, &fs_w))
len = send(fd, buf, 1024*16+67);
}
每次发一定长度的数据,加67是为了使数据长度不是1024的整数倍

另一端不调用recv

发送的前5次,send都返回了…
[/Quote]

对的,select>0时才可以做 send ,recv等操作。==0说明没找到可写可读的socket。<0时就要getlasterror了,看出什么问题了socket。然后作相应处理,一般这时需要closesocket,再重建了。
cnzdgs 2009-01-07
  • 打赏
  • 举报
回复
用非阻塞模式,当要阻塞时会返回失败,错误码是WSAEWOULDBLOCK。
glacier3d 2009-01-07
  • 打赏
  • 举报
回复
这个存在什么问题吗?
TCP的时候,实际send的多少,可以根据返回值判断;
UDP的时候,send时发现缓存不够,应该返回不成功信息吧
dayizhixiaotutu 2009-01-07
  • 打赏
  • 举报
回复
学习
duquanxi 2009-01-07
  • 打赏
  • 举报
回复
up
LichKing 2009-01-07
  • 打赏
  • 举报
回复
study
waitforsomebody 2009-01-07
  • 打赏
  • 举报
回复
会有这种问题,send的粘包问题,现在好像还没有什么好方法解决....

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧