之前我从未使用过UDP,所以我试了一下。为了看看会发生什么,我让“服务器”每半秒发送一次数据,客户端每隔3秒接收一次数据。因此,即使服务器发送的数据比客户端可以接收的速度快得多,客户端仍然可以一个接一个地接收它。
任何人都可以解释为什么/如何发生这种情况?数据在哪里准确缓冲?
发送
class CSimpleSend
{
CSomeObjServer obj = new CSomeObjServer();
public CSimpleSend()
{
obj.changedVar = varUpdated;
obj.threadedChangeSomeVar();
}
private void varUpdated(int var)
{
string send = var.ToString();
byte[] packetData = System.Text.UTF8Encoding.UTF8.GetBytes(send);
string ip = "127.0.0.1";
int port = 11000;
IPEndPoint ep = new IPEndPoint(IPAddress.Parse(ip), port);
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
client.SendTo(packetData, ep);
Console.WriteLine("Sent Message: " + send);
Thread.Sleep(100);
}
}
所有CSomeObjServer都是每半秒递增一个整数
接收
class CSimpleReceive
{
CSomeObjClient obj = new CSomeObjClient();
public Action<string> showMessage;
Int32 port = 11000;
UdpClient udpClient;
public CSimpleReceive()
{
udpClient = new UdpClient(port);
showMessage = Console.WriteLine;
Thread t = new Thread(() => ReceiveMessage());
t.Start();
}
private void ReceiveMessage()
{
while (true)
{
//Thread.Sleep(1000);
IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, port);
byte[] content = udpClient.Receive(ref remoteIPEndPoint);
if (content.Length > 0)
{
string message = Encoding.UTF8.GetString(content);
if (showMessage != null)
showMessage("Recv:" + message);
int var_out = -1;
bool succ = Int32.TryParse(message, out var_out);
if (succ)
{
obj.alterSomeVar(var_out);
Console.WriteLine("Altered var to :" + var_out);
}
}
Thread.Sleep(3000);
}
}
}
CSomeObjClient存储变量并有一个函数(alterSomeVar)来更新它
输出继电器:
Sent Message: 1
Recv:1
Altered var to :1
Sent Message: 2
Sent Message: 3
Sent Message: 4
Sent Message: 5
Recv:2
Altered var to :2
Sent Message: 6
Sent Message: 7
Sent Message: 8
Sent Message: 9
Sent Message: 10
Recv:3
Altered var to :3
答案 0 :(得分:3)
操作系统内核为每个UDP和TCP套接字维护单独的发送和接收缓冲区。如果您使用Google SO_SNDBUF
和SO_RCVBUF
,则可以找到有关它们的大量信息。
发送数据时,会将数据从应用程序空间复制到发送缓冲区。从那里将它复制到网络接口卡,然后复制到电线上。接收方是相反的:接收缓冲区的NIC,它等待你读取它。此外,还可能发生复制和缓冲,具体取决于操作系统。
值得注意的是,这些缓冲区的大小可以根本不同。有些系统可能默认为4千字节,而其他系统则为2兆字节。您可以使用getsockopt()
和SO_SNDBUF
使用SO_RCVBUF
找到当前大小,同样使用setsockopt()
设置它。但是许多系统限制缓冲区的大小,有时限制为任意少量。这通常是内核值,如net.core.wmem_max
或net.core.rmem_max
,但具体参考值因系统而异。
另请注意,即使您请求的金额低于假定的限额,setsockopt()
也会失败。因此,要实际获得所需的大小,您需要使用递减的金额重复调用setsockopt()
,直到它最终成功。
以下页面是我公司的技术说明,它稍微涉及了这个主题并提供了一些常见系统的参考:http://www.dataexpedition.com/support/notes/tn0024.html
答案 1 :(得分:0)
在我看来,UdpClient-Class为接收到的数据提供了一个缓冲区。尝试直接使用套接字。您可能还希望将套接字ReceiveBufferSize设置为零,即使我认为它仅用于TCP连接。