我之前从未使用过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);
}
}
Run Code Online (Sandbox Code Playgroud)
所有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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
操作系统内核为每个 UDP 和 TCP 套接字维护单独的发送和接收缓冲区。如果你用谷歌搜索SO_SNDBUF,SO_RCVBUF你会发现很多关于它们的信息。
当您发送数据时,数据会从您的应用程序空间复制到发送缓冲区中。它从那里复制到网络接口卡,然后复制到线路上。接收端则相反:NIC 接收缓冲区,它会在那里等待,直到您读取它。此外,根据操作系统的不同,也可能会发生复制和缓冲。
值得注意的是,这些缓冲区的大小可能会有很大差异。有些系统可能默认为 4 KB,而其他系统则为 2 MB。getsockopt()您可以使用或找到当前大小SO_SNDBUF,SO_RCVBUF并同样使用 进行设置setsockopt()。但许多系统限制缓冲区的大小,有时限制为任意小量。这通常是一个内核值,例如net.core.wmem_max或net.core.rmem_max,但确切的参考值会因系统而异。
另请注意,setsockopt()即使您请求的金额低于假定的限制,也可能会失败。因此,要真正获得所需的大小,您需要setsockopt()使用递减的数量重复调用,直到最终成功。
以下页面是我公司的技术说明,其中稍微涉及此主题并提供一些常见系统的参考:http://www.dataexpedition.com/support/notes/tn0024.html