Windows 如果套接字的内核缓冲区有足够的空间容纳至少1个字节,但没有足够的空间容纳正在发送的所有字节,则返回的字节数少于请求的字节数

Windows 如果套接字的内核缓冲区有足够的空间容纳至少1个字节,但没有足够的空间容纳正在发送的所有字节,则返回的字节数少于请求的字节数,windows,sockets,tcp,winsock,blocking,Windows,Sockets,Tcp,Winsock,Blocking,因此,如果我想确保将指定数量的字节发送到套接字缓存中,我想我应该使用sendToCnt()而不是发送: private int sendToCnt(Socket socket, byte[] buf, int beginIndex, int cnt) { if (buf.Length < beginIndex + cnt) return 0; int realCnt = 0; while (realCnt < cnt) { realC

因此,如果我想确保将指定数量的字节发送到套接字缓存中,我想我应该使用
sendToCnt()
而不是发送:

private int sendToCnt(Socket socket, byte[] buf, int beginIndex, int cnt)
{
   if (buf.Length < beginIndex + cnt)
      return 0;

   int realCnt = 0;
   while (realCnt < cnt)
   {
      realCnt += socket.Send(buf, beginIndex + realCnt, cnt - realCnt, SocketFlags.None);
   }
   return realCnt;
}

是。

“您发布的[recvToCnt()]代码会忽略错误并完全终止流”-套接字错误会引发异常
recvToCnt()
不需要直接处理异常,让调用方决定如何处理它们。但您是对的,它至少需要处理流的末尾<代码>接收()当套接字正常关闭时返回0。“您发布的[sendToCnt()]代码会忽略错误”-
Send()
不会在出现错误时返回值,它会引发异常,包括套接字关闭时的异常。因此
sendToCnt()
不需要处理错误,让调用者来处理。“Send()的返回值在非阻塞模式下变得非常重要。在阻塞模式下,它的行为如所述”-不,即使在阻塞模式下,它也可以返回比请求更少的字节(尽管可能不需要)。因此,您也必须在循环中调用
Send()
。@Remy:重要的是要注意,问题是关于套接字API周围未指定的面向对象包装器,而不是Winsock函数。(它的标签有点错了)。可能包装器的行为与底层套接字API稍有不同。@BenVoigt所讨论的包装器是.NET的
socket
类(引号来自MSDN的
socket
文档)。我所说的适用于那个班。我检查了它的源代码,它不会在内部循环以确保在退出之前读取/发送所有请求的字节,因此您必须在自己的代码中循环,就像我们使用Winsock函数一样directly@RemyLebeau
Receive()。关于
Send()
,您在这里与MSDN争论,而不是与我争论。Posix还表示,对于BSD套接字API和Posix
write()
方法,在阻塞模式下必须如此,除非发生中断,其语义我27年来一直无法理解。这是一个需要争论的主要来源。“您发布的[recvToCnt()]代码会忽略错误并完全终止流”-套接字错误会引发异常
recvToCnt()
不需要直接处理异常,让调用方决定如何处理它们。但您是对的,它至少需要处理流的末尾<代码>接收()
当套接字正常关闭时返回0。“您发布的[sendToCnt()]代码会忽略错误”-
Send()
不会在出现错误时返回值,它会引发异常,包括套接字关闭时的异常。因此
sendToCnt()
不需要处理错误,让调用者来处理。“Send()的返回值在非阻塞模式下变得非常重要。在阻塞模式下,它的行为如所述”-不,即使在阻塞模式下,它也可以返回比请求更少的字节(尽管可能不需要)。因此,您也必须在循环中调用
Send()
。@Remy:重要的是要注意,问题是关于套接字API周围未指定的面向对象包装器,而不是Winsock函数。(它的标签有点错了)。可能包装器的行为与底层套接字API稍有不同。@BenVoigt所讨论的包装器是.NET的
socket
类(引号来自MSDN的
socket
文档)。我所说的适用于那个班。我检查了它的源代码,它不会在内部循环以确保在退出之前读取/发送所有请求的字节,因此您必须在自己的代码中循环,就像我们使用Winsock函数一样directly@RemyLebeau
Receive()。关于
Send()
,您在这里与MSDN争论,而不是与我争论。Posix还表示,对于BSD套接字API和Posix
write()
方法,在阻塞模式下必须如此,除非发生中断,其语义我27年来一直无法理解。这有很多主要来源需要争论。如果另一方关闭连接或出现错误,则您的
recvToCnt
代码将以无休止的循环方式旋转。@DavidSchwartz如果发生错误,将引发异常。但你对对方关闭连接的看法是正确的。代码需要处理以下情况:
Receive()
返回0表示连接已正常关闭。
recvToCnt
如果另一端关闭连接或出现错误,代码将以无休止的循环方式旋转。@DavidSchwartz如果发生错误,将引发异常。但你对对方关闭连接的看法是正确的。代码需要处理以下情况:
Receive()
返回0以指示连接已正常关闭。
private int sendToCnt(Socket socket, byte[] buf, int beginIndex, int cnt)
{
   if (buf.Length < beginIndex + cnt)
      return 0;

   int realCnt = 0;
   while (realCnt < cnt)
   {
      realCnt += socket.Send(buf, beginIndex + realCnt, cnt - realCnt, SocketFlags.None);
   }
   return realCnt;
}