簡體   English   中英

如何正確進行異步udp網絡?

[英]How to do async udp networking right?

就像這里的許多其他人一樣,我正在嘗試創建一個網絡庫。 需求基本上是這樣的:

  • 異步工作並為實時應用程序做好准備(我考慮的是 FPS 游戲)
  • 使用 UDP 並根據需要在頂部設置一個薄協議層
  • 本機使用 IPv6
  • 支持多個平台(閱讀:我想要 Mono 支持!)

現在在閱讀了一些關於如何做到這一點(最鼓舞人心的是Gaffer on Games )之后,我設置了我的開發環境,思考如何做到這一點並提出了這個基本的工作流程:

  1. 初始化套接字並告訴它使用“UDPv6”
  2. 將該套接字綁定到端口並使異常不會打擾用戶。 有一個“綁定”屬性告訴他套接字設置正確。
  3. 了解本地計算機支持的 ​​NIC 的最大 MTU。
  4. 初始化多個 SocketAsyncEventArgs,告訴它的 Completed 事件調用私有調度方法並將其緩沖區設置為步驟 3 中的最大 MTU 的大小。
  5. 使用第一個 SAEA 對象調用 Sockets ReceiveFromAsync 方法。

當數據進來時,我執行以下操作:

  1. 使用下一個空閑的 SAEA 對象調用 ReceiveFromAsync 方法
  2. 從當前 SAEA 對象中獲取緩沖區和發送者信息並使其再次可用
  3. 使用接收到的消息觸發一個新事件。

我對這種方法做了一些測試,效果很好。 我每 10 毫秒向它發送一條消息,其中包含 200 字節的數據,持續 10000 個周期,並且 CPU 或內存負載幾乎沒有增加。 只有 NIC 負載在增加。 然而我想出了一些問題| 問題:

  • 當我處置我的 PeerSocket 類(即持有套接字)時,我處置了每個 SAEA 對象。 但由於其中至少有一個仍在偵聽新消息,因此拋出 ObjectDisposedException。 有沒有辦法讓它停止聆聽?
  • MTU 可能在通往其他對等方的路上有所不同,也許每個 SAEA 對象的緩沖區應該使用不同的指標來確定緩沖區大小?
  • 我還不確定如何處理碎片化的數據報。 我將繼續將“可靠性標頭”寫入我正在發送的數據報中,但是如果數據報被拆分,我不知道此標頭信息,對嗎?

該庫有望有一天對其他人有用,並且它的存儲庫是公開可用的。 就這個問題而言,當前的提交可以在這里找到

哇,這真是一個巨大的主題。 如果您在學習之前沒有了解網絡套接字。 我可以給你要點,但這絕對不夠。

客戶:

public void Get()
    {
        string data;
        string input;
        IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050);

        Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);


        try
        {
            socket.Connect(ipep);
        }
        catch (SocketException e)
        {
            Console.WriteLine("Unable to connect to server");
            Console.WriteLine(e.ToString());
            return;
        }

        NetworkStream ns = new NetworkStream(socket);
        StreamWriter sw = new StreamWriter(ns);
        StreamReader sr = new StreamReader(ns);

        data = sr.ReadLine();
        Console.WriteLine(data);

        while (true)
        {
            input = Console.ReadLine();
            if (input == "exite")
                break;

            sw.WriteLine(input);
            sw.Flush();

            data = sr.ReadLine();
            Console.WriteLine(data);
        }
        Console.WriteLine("Disconnected from server...");
        socket.Close();
        ns.Close();
        sr.Close();
        sr.Close();
    }

服務器:

public void Get()
    {
        string data;
        IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);

        Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        socket.Bind(ipep);
        socket.Listen(10);
        Console.WriteLine("Waiting for a client...");

        Socket client = socket.Accept();
        IPEndPoint newclient = (IPEndPoint)client.RemoteEndPoint;
        Console.WriteLine("Connected with: {0}, at Port: {1}", newclient.Address, newclient.Port);

        NetworkStream ns = new NetworkStream(client);
        StreamReader sr = new StreamReader(ns);
        StreamWriter sw = new StreamWriter(ns);

        string welcome = "Welcome to my test server";
        sw.Write(welcome);
        sw.Flush();

        while (true)
        {
            try
            {
                data = sr.ReadLine();
            }
            catch (IOException)
            {
                break;
            }
            Console.WriteLine(data);
            sw.WriteLine(data);
            sw.Flush();
        }
        Console.WriteLine("Disconnected from {0}", newclient.Address);
        sw.Close();
        ns.Close();
        sr.Close();
    }

請在控制台應用程序上嘗試一下,看看它是如何工作的。

基本上,服務器打開端口(本例中為 9050)等待客戶端連接,然后客戶端連接到服務器,然后開始通信。

你提到你必須使用 UDP 套接字,我想你知道 udp 但如果不是你最好檢查一下 TCP 和 UDP 之間的區別,特別是關於驗證數據到達所需目的地的方式(臨時概念等等上)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM