嘗試使用時,UdpClient.Receive我注意到它只回傳一個位元組陣列。這會為每個資料包分配一個新的緩沖區嗎?據我所知,為每個收到的資料包分配一個新的位元組陣列對性能和記憶體使用不利。為了在使用 Tcp 時解決同樣的問題,我使用了一個 ArrayPool 來租用緩沖區。但是我將如何使用 Udp 做到這一點?
我考慮過使用與 Tcp 相同的方法并僅使用套接字,但是 udp 不是基于流的,因此這種方法沒有什么意義(我不知道一個資料包會有多大,我不能不斷地從流中讀取在 TCP 中)。
TL;博士:
如何在接收 UDP 資料包的同時始終接收完整資料包時節省性能?
uj5u.com熱心網友回復:
嘗試使用時,
UdpClient.Receive我注意到它只回傳一個位元組陣列。這會為每個資料包分配一個新的緩沖區嗎?
通常,是的。
在內部,UdpClient使用固定大小的byte[65536]陣列來讀取每個資料包。如果接收到的資料包恰好是該大小,則內部緩沖區按原樣回傳。但是,如果接收到的資料包小于該大小(通常是這種情況),則它會分配一個新byte[]的實際資料包大小,將內部緩沖區的資料復制到該新陣列中,然后將其回傳。
不知道一包有多大
在 Winsock API 中可以確定下一個資料包的實際大小,而無需從套接字佇列中提取資料包。Winsock 的recvfrom()函式有一個MSG_PEEK用于此目的的標志。
UdpClient.Receive()不支持該標志,但是UdpClient' 的基礎Socket在其ReceiveFrom()方法中確實如此,例如:
byte[] ignore = new byte[0]; // the buffer parameter of ReceivFrom() can't be null!
EndPoint ep;
int size = UdpClient.Client.ReceiveFrom(ignore, SocketFlags.Peek, ref ep);
// obtain a buffer of sufficient size ...
UdpClient.Client.ReceiveFrom(buffer, size, SocketFlags.None, ref ep);
雖然Socket.ReceiveFrom()確實允許一個長度為 0 的byte[]陣列(它將向 Winsock 傳遞一個 NULL 指標和 0 緩沖區長度recvfrom()),但我不確定是否會實際回傳下一個資料包大小,或者如果你嘗試Socket.ReceiveFrom()它會拋出一個使用小于實際資料包SocketException的陣列查看佇列(因為我不確定使用標志時byte[]是否recvfrom()報告WSAEMSGSIZE錯誤)。MSG_PEEK
為避免此潛在問題,請繼續閱讀...
如何在接收 UDP 資料包的同時始終接收完整資料包時節省性能?
我建議您只使用單個 64Kbyte[]陣列(就像UdpClient內部一樣),而不是嘗試池化陣列,因為 UDP 資料包永遠不會超過該大小。只需UdpClient.Client.ReceiveFrom()直接使用而不是使用UdpClient.Receive(),例如:
byte[] myBuffer = new byte[65536];
EndPoint ep;
...
int received = UdpClient.Client.ReceiveFrom(myBuffer, ref ep);
// use myBuffer up to received bytes ...
// use (IPEndPoint)ep if needed ...
...
這樣,您可以重復使用單個byte[]陣列進行多次讀取(就像UdpClient內部一樣)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/464124.html
上一篇:async和await的實作原理
下一篇:陣列在一行中生成
