为什么假设 send 可能返回的数据少于在阻塞套接字上传输的请求数据? [英] Why is it assumed that send may return with less than requested data transmitted on a blocking socket?

查看:24
本文介绍了为什么假设 send 可能返回的数据少于在阻塞套接字上传输的请求数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在流套接字上发送数据的标准方法一直是调用 send 并写入一大块数据,检查返回值以查看是否所有数据都已发送,然后再次调用 send 直到整个消息都已发送接受.

例如,这是一个常见方案的简单示例:

<前>int send_all(int sock, unsigned char *buffer, int len) {意图;而(长度> 0){nsent = send(sock, buffer, len, 0);if(nsent == -1)//错误返回-1;缓冲区 += nsent;len -= nsent;}返回0;//好的,所有数据发送}

即使是 BSD 联机帮助页也提到

...如果套接字上没有可用的消息空间来保存要传输的消息,则 send() 通常会阻塞...

这表明我们应该假设 send 可能会在不发送所有数据的情况下返回.现在我发现这相当糟糕,但即使是 W. Richard Stevens 在他关于 网络编程<的标准参考书中也假设了这一点/a>,不是在开头的章节,而是更高级的例子使用他自己的writen(写入所有数据)函数而不是调用write.

现在我认为这仍然或多或少被破坏了,因为如果send无法传输所有数据或接受底层缓冲区中的数据并且套接字被阻塞,那么send应该在整个send请求时阻塞并返回已被接受.

我的意思是,在上面的代码示例中,如果发送返回的数据较少,将会发生什么情况是它将在新请求中再次被调用.自上次通话以来发生了什么变化?最多几百个 CPU 周期已经过去,所以缓冲区仍然是满的.如果send现在接受数据为什么之前不能接受?

否则,我们将以低效循环结束,我们将尝试在无法接受数据的套接字上发送数据并继续尝试,否则?

因此,如果需要,解决方法似乎会导致代码效率极低,在这种情况下,应完全避免阻塞套接字,而应改用非阻塞套接字和 select.

上面描述中缺少的一点是,在 Unix 中,系统调用可能会被信号中断.这正是阻塞 send(2) 可能返回短计数的原因.

The standard method to send data on a stream socket has always been to call send with a chunk of data to write, check the return value to see if all data was sent and then keep calling send again until the whole message has been accepted.

For example this is a simple example of a common scheme:

int send_all(int sock, unsigned char *buffer, int len) {
  int nsent;

  while(len > 0) {
    nsent = send(sock, buffer, len, 0);
    if(nsent == -1) // error
      return -1;

    buffer += nsent;
    len -= nsent;
  }
  return 0; // ok, all data sent
}

Even the BSD manpage mentions that

...If no messages space is available at the socket to hold the message to be transmitted, then send() normally blocks...

Which indicates that we should assume that send may return without sending all data. Now I find this rather broken but even W. Richard Stevens assumes this in his standard reference book about network programming, not in the beginning chapters, but the more advanced examples uses his own writen (write all data) function instead of calling write.

Now I consider this still to be more or less broken, since if send is not able to transmit all data or accept the data in the underlying buffer and the socket is blocking, then send should block and return when the whole send request has been accepted.

I mean, in the code example above, what will happen if send returns with less data sent is that it will be called right again with a new request. What has changed since last call? At max a few hundred CPU cycles have passed so the buffer is still full. If send now accepts the data why could'nt it accept it before?

Otherwise we will end upp with an inefficient loop where we are trying to send data on a socket that cannot accept data and keep trying, or else?

So it seems like the workaround, if needed, results in heavily inefficient code and in those circumstances blocking sockets should be avoided at all an non blocking sockets together with select should be used instead.

解决方案

The thing that is missing in above description is, in Unix, system calls might get interrupted with signals. That's exactly the reason blocking send(2) might return a short count.

这篇关于为什么假设 send 可能返回的数据少于在阻塞套接字上传输的请求数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆