我想更好地理解套接字实现的非阻塞send
。
鉴于我使用了一个非阻塞套接字,并使用char缓冲区“ buf”发送了数据,而send
返回了EAGAIN
错误。我可以假定“ buf”内容已复制到POSIX框架/网络堆栈中的内部缓冲区中,并且我可以使用“ buf”将新数据发送到套接字,或者EAGAIN
表示“ buf”将在以后复制,因此不应该更改“ buf”内存?
我对此进行了很多搜索,但是没有找到明确的答案。
对于aio_write
,我在手册页中发现以下注释:
不得访问正在写出的缓冲区 在操作过程中可能会出现不确定的结果。记忆 涉及的区域必须保持有效。
但是对于非阻塞,我没有找到类似的东西。
谢谢。
答案 0 :(得分:2)
重要的是要理解非阻塞I / O和异步I / O是不同的模型。
在使用非阻塞I / O时,每个send
或recv
都会立即发生,但前提是必须在不阻塞调用过程的情况下完成它。这意味着,对于send
,内核套接字缓冲区中至少有一些空间可以发送数据。对于recv
,至少要接收一些数据字节。在这些情况下,调用将“成功”,分别返回发送或接收的字节数。否则,调用将失败,返回-1
并将errno
设置为EAGAIN
(并且不会向您的缓冲区发送或接收任何内容,也不会从缓冲区复制任何内容)。
另一方面,aio_write
(和aio_read
)是真正异步的:这些调用将一个I / O操作排队,即使无法立即进行也将继续进行。当您的进程执行其他操作时,内核将继续监视和“托管”请求。因此,对于aio_write
,该操作可以立即完成,也可以在以后的某个时间完成。无论哪种情况,您要么必须轮询完成,要么使用sigevent
机制来通知完成情况-如aio(7)
和sigevent(7)
手册页中所述。
在执行aio_write
之后修改缓冲区的注意事项是因为您已经加入了写操作,但是内核并不一定要占用缓冲区,因此,如果要修改其内容,则不确定是否要删除缓冲区。消耗旧内容或新内容。
同样的警告将(并且确实)适用于修改普通send
(无论是阻塞还是非阻塞)期间 send
通话正在进行中。但是,由于普通的send
与发送线程是同步的,因此,唯一的方法是在原始线程中执行send
操作时,通过另一个线程对其进行修改。>
答案 1 :(得分:1)
send(2)的手册页指出:
EAGAIN或EWOULDBLOCK
套接字被标记为非阻塞且请求的操作 会阻止。 POSIX.1-2001允许返回任一错误 在这种情况下,不需要这些常量具有 相同的值,因此便携式应用程序应检查 两种可能性。
鉴于您正在使用非阻塞I / O来解释这一点,请执行以下操作:
套接字另一端的接收器正忙,尚未准备好接收数据。因此,您可以假定buf
的内容尚未使用(也没有复制到内核中)
仅供参考:您可以通过在套接字的文件描述符上执行select(2)来确定何时准备接收数据,来防止出现此错误。
答案 2 :(得分:1)
...返回,但出现EAGAIN错误。我可以假设“ buf”内容已复制到内部缓冲区
否,该错误表示未复制任何内容,您需要重试整个缓冲区。
请记住,您还应该检查非错误返回值,因为它可能会成功写入缓冲区的 part 。
我对此进行了很多搜索,但是没有找到明确的答案
好的,我同意手册页对此不是很明确。相反,让我们看一下接口,并考虑调用它时可能发生的情况:
ssize_t result = send(sockfd, buf, len, 0);
if (result < 0) {
/* we have an error, so examine errno */
return;
}
if (result == len) {
/* we sent the whole buffer and can reuse buf at will */
}
else {
/* 0 <= result < len, so we sent some of buf, but not all.
* It's not an error but we need to keep buf[result..len] for later
*/
}
这三个分支覆盖了所有可能的情况-它不能返回它们所覆盖的其他 。
它要么发送什么东西,要么什么都不发送,如果发送了什么东西,我们需要知道多少字节。
它要么成功(返回> = 0),要么失败,如果失败,我们 也不知道发送了多少字节。
因此,编写此接口的唯一明智的方法是在出现错误时不发送任何字节-否则,我们将处于不确定状态(我们无法确定是否需要一些,全部或全部buf)待重试)。
我认为这里还有另一个误解:
我可以假设将“ buf”内容复制到POSIX框架/网络堆栈中的内部缓冲区中
这就是发送成功时发生的情况。成功返回并不意味着您的数据已被接收,甚至不实际发送:仅表示操作系统已承担了传递数据的责任。
因此,在您的建议中,成功与失败之间没有区别。
答案 3 :(得分:0)
我可以假设将“ buf”内容复制到POSIX框架/网络堆栈中的内部缓冲区中
当然不是。这就是为什么它告诉您再试一次。什么都没转移。
我可以使用“ buf”将新数据发送到套接字
否。
或EAGAIN表示“ buf”中的数据将在以后复制
在您重试发送之前,它将永远不会被复制。
并且不应该更改“ buf”内存?
您可以按照自己的喜好进行操作,但是如果要重试,最好不要先更改它。
我对此进行了很多搜索,但没有找到明确的答案。
很难相信。您的搜索应该从Sub deleteColumns()
Dim c As Long
Dim i As Long
i = 800
For c = i To 1 Step -1
If Trim(Cells(2, c).Value) = vbNullString Or Cells(2, c).Value < 250 Or Cells(2, c).Value > 1000 Then
Columns(c).Delete
End If
Next
End Sub
的 man 页开始。
对于
send()
,我在手册页中发现以下注释:
不育。之所以这样说是因为尚未写入数据,而是将在异步I / O处理完该数据时进行。与非阻止模式无关。