[英]is it possible to have multiple UDP c# sockets with same localEndPoint?
我寫了一個工作正常的 TCP 客戶端/服務器代碼。 TCP 套接字偵聽器接受連接並創建許多具有相同 localEndPoint 和各種 RemoteEndPoint 的套接字。 現在我想擴展到 UDP,但我在服務器代碼中遇到了問題。 我必須將 UDP 套接字綁定到每個客戶端對象的 localEndPoint。 但我遇到了一個錯誤:我無法使用相同的 localEndPoint 綁定多個 UDP 套接字。 根據Wiki ,我發現這是 UDP 套接字的性質:
UDP 服務器不會為每個並發服務的客戶端創建新的子進程,但同一進程通過同一套接字順序處理來自所有遠程客戶端的傳入數據包。 這意味着 UDP 套接字不是由遠程地址標識的,而是僅由本地地址標識的,盡管每條消息都有一個關聯的遠程地址。
那么我可以像為 TCP 套接字那樣為每個客戶端創建一個不同的 UDP 套接字嗎?
注意:如果可能,請用socket
類解釋,而不是UDPClient
類。
private void SocketAsyncEventArgs_Completed(object sender, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Accept:
case SocketAsyncOperation.Connect:
UDP.Bind(TCP.LocalEndPoint);
代碼解釋:我以為我可以在建立TCP連接(連接/接受)后在雙方(客戶端/服務器)綁定一個UDP套接字。 服務器上只有一個客戶端是可以的。 對於新客戶端,服務器會拋出異常,因為它無法將多個套接字與一個 localEndPoint 綁定。 並且客戶端可以超過所有可用端口。 所以我無法為每個客戶端將 UDP 套接字綁定到不同的 localEndPoint。
我知道我可以創建一個唯一的 UDP 套接字並將接收消息傳遞給服務器上的相應客戶端對象,但這有點討厭。 謝謝!
您可以為每個唯一的源 IP:Port 組合運行一個任務。 這將允許您輕松維護每個唯一傳入源 IP:PORT 組合的狀態機。 System.IO.Pipelines
可以很容易地將它們結合在一起。
首先設置一個類似於TCPListener
的UDPListener
任務,對於每個新 IP:PORT 啟動一個任務來處理該端口,創建一個 Pipe 並且每個時間數據來自該 IPEndpoint,將數據放入PipeWriter
static async Task StartUdpListener()
{
// Use a Dictionary to match packets from given connections to give Pipes
ConcurrentDictionary<string, Pipe> connections = new ConcurrentDictionary<string, Pipe>();
var udpServer = new UdpClient(new IPEndPoint(IPAddress.Any, 33000));
while (true)
{
// Wait for some data to arrive
var result = await udpServer.ReceiveAsync();
if(connections.ContainsKey(result.RemoteEndPoint.ToString()))
{
// If we have seen this IPEndpoint before send the traffic to the pipe
// the task associated with that Pipe willpick the traffic up
connections.TryGetValue(result.RemoteEndPoint.ToString(), out var p);
await p.Writer.WriteAsync(result.Buffer);
}
else
{
// If we have not seen it, make the pipe, stick the data in the pipe
// and spin up a task to Read/Process the data
var p = new Pipe();
connections.TryAdd(result.RemoteEndPoint.ToString(), p);
await p.Writer.WriteAsync(result.Buffer);
_ = Task.Run(() => UdpServerClient(result.RemoteEndPoint.ToString(), p));
}
}
}
這是內核在接收 TCPPacket 時執行的操作的一個簡單視圖,它將它粘貼在套接字緩沖區中供您通過流讀取。
UDP Server Client
任務看起來像這樣:
static async Task UdpServerClient(string serverName,Pipe p)
{
while (true)
{
var readResult = await p.Reader.ReadAsync();
var message = Encoding.ASCII.GetString(readResult.Buffer.FirstSpan.ToArray());
Console.WriteLine($"Server: {serverName} Received: {message}");
p.Reader.AdvanceTo(readResult.Buffer.End);
}
}
為了完整起見,一些客戶端通常位於不同的機器上,但為了簡單起見,我們將它們作為任務運行。
static async Task UdpClientClient(string messageToSend)
{
var client = new UdpClient();
client.Connect("127.0.0.1", 33000);
for(var i=0;i<5;i++)
{
var message = ASCIIEncoding.ASCII.GetBytes(messageToSend + " #"+ i.ToString());
await client.SendAsync(message, message.Length);
await Task.Delay(1000);
}
}
}
將它們鏈接在一起:
static async Task Main(string[] args)
{
_ = Task.Run(() => StartUdpListener());
_ = UdpClientClient("hi Server!");
_ = UdpClientClient("I am here server...");
await UdpClientClient("Me too server!");
}
你會得到這個:
Server: 127.0.0.1:53183 Received: Me too server! #0
Server: 127.0.0.1:53182 Received: I am here server... #0
Server: 127.0.0.1:53181 Received: hi Server! #0
Server: 127.0.0.1:53182 Received: I am here server... #1
Server: 127.0.0.1:53183 Received: Me too server! #1
Server: 127.0.0.1:53181 Received: hi Server! #1
Server: 127.0.0.1:53182 Received: I am here server... #2
Server: 127.0.0.1:53183 Received: Me too server! #2
Server: 127.0.0.1:53181 Received: hi Server! #2
Server: 127.0.0.1:53182 Received: I am here server... #3
Server: 127.0.0.1:53181 Received: hi Server! #3
Server: 127.0.0.1:53183 Received: Me too server! #3
Server: 127.0.0.1:53183 Received: Me too server! #4
Server: 127.0.0.1:53181 Received: hi Server! #4
Server: 127.0.0.1:53182 Received: I am here server... #4
當然,您需要進行錯誤檢查,查看客戶端是否仍然存在等。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.