Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#UDP套接字未从正确的端口接收消息_C#_.net_Sockets_Asynchronous_Udp - Fatal编程技术网

C#UDP套接字未从正确的端口接收消息

C#UDP套接字未从正确的端口接收消息,c#,.net,sockets,asynchronous,udp,C#,.net,Sockets,Asynchronous,Udp,我创建了一个测试驱动程序来模拟另一个程序的问题: EDIT2:这段代码在很大程度上可以忽略,第二段代码可能更简洁 using System; using System.Net; using System.Text; using System.Net.Sockets; namespace TestAsyncSockets { class Program { /// <summary> /// Object to send back an

我创建了一个测试驱动程序来模拟另一个程序的问题:
EDIT2:这段代码在很大程度上可以忽略,第二段代码可能更简洁

using System;
using System.Net;
using System.Text;
using System.Net.Sockets;

namespace TestAsyncSockets
{
    class Program
    {
        /// <summary>
        /// Object to send back and forth along with datagrams
        /// </summary>
        class State
        {
            /// <summary>
            /// Socket that started async receive
            /// </summary>
            public Socket S;

            /// <summary>
            /// Endpoint that data was received from
            /// </summary>
            public EndPoint E;

            /// <summary>
            /// Buffer where received data is stored
            /// </summary>
            public byte[] Buffer;
        }

        private const int SERVER_PORT = 50000;

        private const int SERVER_CMD_SEND_PORT = 50001;

        private const int CLIENT_PORT = 50002;

        private static readonly IPAddress s_LocalHost = new IPAddress(new byte[] {127, 0, 0, 1});

        private static readonly StringBuilder s_Logger = new StringBuilder();

        private static readonly object s_Locker = new object();

        /// <summary>
        /// Test async sockets
        /// </summary>
        static void Main()
        {
            // Server receives commands on SERVER_PORT from anyone and calls CommandReceived
            CreateReceiver(s_LocalHost, SERVER_PORT, IPAddress.Any, 0, ServerCommandReceived);

            // Client receives Acks on CLIENT_PORT from SERVER_PORT and calls ResponseReceived
            CreateReceiver(s_LocalHost, CLIENT_PORT, s_LocalHost, SERVER_PORT, ClientResponseReceived);

            // Client receives commands on CLIENT_PORT from SERVER_CMD_SEND_PORT and calls 
            CreateReceiver(s_LocalHost, CLIENT_PORT, s_LocalHost, SERVER_CMD_SEND_PORT, ClientCommandReceived);

            // Client sends commands from CLIENT_PORT to SERVER_PORT
            CreateSender(s_LocalHost, CLIENT_PORT, s_LocalHost, SERVER_PORT, Encoding.ASCII.GetBytes("ClientCmd"));

            // Server sends commands from SERVER_CMD_SEND_PORT to CLIENT_PORT
            CreateSender(s_LocalHost, SERVER_CMD_SEND_PORT, s_LocalHost, CLIENT_PORT, Encoding.ASCII.GetBytes("ServerCmd"));

            // Wait for messages to be received (hack for test code only)
            System.Threading.Thread.Sleep(5000);
            System.IO.File.AppendAllText("C:\\log.txt", s_Logger.ToString());
            Console.WriteLine(s_Logger.ToString());
            Console.ReadLine();
        }

        /// <summary>
        /// Creates a socket to send data
        /// </summary>
        private static void CreateSender(IPAddress localIp, int localPort, IPAddress remoteIp, int remotePort, byte[] dataToSend)
        {
            // Create socket for sending
            Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

            // Allow other Sockets to bind to its local end point
            sender.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

            // Create local end point and bind to it
            IPEndPoint localEndPoint = new IPEndPoint(localIp, localPort);
            sender.Bind(localEndPoint);

            // Create remote end point to send to
            EndPoint remoteEndPoint = new IPEndPoint(remoteIp, remotePort);

            // Send and log
            sender.SendTo(dataToSend, remoteEndPoint);
            string message = string.Join("", Encoding.ASCII.GetChars(dataToSend));
            LogStatement("Sent " + message + " from " + localEndPoint + " to " + remoteEndPoint);
        }

        /// <summary>
        /// Creates socket to receive a message and call async method
        /// </summary>
        private static void CreateReceiver(IPAddress localIp, int localPort, IPAddress remoteIp, int remotePort, AsyncCallback messageReceived)
        {
            // Create UDP socket
            Socket receiver = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

            // Create local endpoint to bind to
            IPEndPoint localEndPoint = new IPEndPoint(localIp, localPort);

            // Allow other Sockets to bind to this local end point too
            receiver.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

            // Bind to local endpoint
            receiver.Bind(localEndPoint);

            // Create remote endpoint
            EndPoint remoteEndPoint = new IPEndPoint(remoteIp, remotePort);

            // Create state object for async callback
            State receiveState = new State { S = receiver, E = remoteEndPoint, Buffer = new byte[100] };

            // Begin receiving message from remote endpoint
            // Call messageReceived callback when done
            receiver.BeginReceiveFrom(receiveState.Buffer, 0, 100, SocketFlags.None, ref remoteEndPoint, messageReceived, receiveState);
            LogStatement("Receiving on " + localEndPoint + " from " + remoteEndPoint + " and will call " + messageReceived.Method.Name);
        }

        /// <summary>
        /// Method called when server receives command
        /// </summary>
        private static void ServerCommandReceived(IAsyncResult ar)
        {
            LogStatement("In ServerCommandReceived");
            State state = (State)ar.AsyncState;
            try
            {
                int bytes = state.S.EndReceiveFrom(ar, ref state.E);    // End recieve and get data
                if (bytes > 0)
                {
                    byte[] actualMessage = new byte[bytes];
                    Buffer.BlockCopy(state.Buffer, 0, actualMessage, 0, bytes);
                    string message = string.Join("", Encoding.ASCII.GetChars(actualMessage));
                    LogStatement("Received " + message + " on " + state.S.LocalEndPoint + " from " + state.E);
                }
            }
            catch (SocketException se)
            {
                LogStatement(se.ToString());
            }

            // We just received a command. Send a response back to the port that sent the command (state.E)
            state.S.SendTo(Encoding.ASCII.GetBytes("Response"), state.E);
            LogStatement("Sent " + "Response" + " from " + state.S.LocalEndPoint + " to " + state.E);

            state.S.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.E, ServerCommandReceived, state);
        }

        /// <summary>
        /// Method called when client receives a command response
        /// </summary>
        private static void ClientResponseReceived(IAsyncResult ar)
        {
            LogStatement("In ClientResponseReceived");
            State state = (State)ar.AsyncState;
            try
            {
                int bytes = state.S.EndReceiveFrom(ar, ref state.E);
                if (bytes > 0)
                {
                    byte[] actualMessage = new byte[bytes];
                    Buffer.BlockCopy(state.Buffer, 0, actualMessage, 0, bytes);
                    string message = string.Join("", Encoding.ASCII.GetChars(actualMessage));
                    LogStatement("Received " + message + " on " + state.S.LocalEndPoint + " from " + state.E);
                }
            }
            catch (SocketException se)
            {
                Console.WriteLine(se.ToString());
            }

            state.S.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.E, ClientResponseReceived, state);
        }

        /// <summary>
        /// Method called when client receives a server command
        /// </summary>
        private static void ClientCommandReceived(IAsyncResult ar)
        {
            LogStatement("In ClientCommandReceived");
            State state = (State)ar.AsyncState;
            try
            {
                int bytes = state.S.EndReceiveFrom(ar, ref state.E);
                if (bytes > 0)
                {
                    byte[] actualMessage = new byte[bytes];
                    Buffer.BlockCopy(state.Buffer, 0, actualMessage, 0, bytes);
                    string message = string.Join("", Encoding.ASCII.GetChars(actualMessage));
                    LogStatement("Received " + message + " on " + state.S.LocalEndPoint + " from " + state.E);
                }
            }
            catch (SocketException se)
            {
                LogStatement(se.ToString());
            }

            state.S.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.E, ClientCommandReceived, state);
        }

        /// <summary>
        /// Thread safe logging (hopefully)
        /// </summary>
        /// <param name="s"></param>
        private static void LogStatement(string s)
        {
            lock (s_Locker)
            {
                s_Logger.AppendLine(s);
            }
        }
    }
}

现在我看到每个receive方法调用一次!不幸的是,我仍然感到困惑,因为当从50000收到消息时应该调用ClientResponseReceived,当从50001收到消息但它们被切换时应该调用ClientCommandReceived。不确定这是参考问题还是Windows套接字问题。

UDP更类似于广播协议,类似于广播电台,它只发送内容供任何接收器接收。因此,您两次接收同一数据包的描述是由两个接收器侦听引起的。除了“定向广播”之外,如果您想确定点对点关系,它将在应用层进行,因为UDP(如果我没记错的话)没有实现这个概念。@JohnPeters很抱歉造成混淆。我不会两次收到相同的消息。我在同一个接收器上接收两条消息,而我希望一个接收器接收一条消息,另一个接收器接收另一条消息。如果UDP更像广播,那么C#“SendTo”方法是谎言吗?@JohnPeters,我认为可以使用UDP在特定端口监听。UDP更像广播协议,类似于广播电台,它只发送内容供任何接收器接收。因此,您两次接收同一数据包的描述是由两个接收器侦听引起的。除了“定向广播”之外,如果您想确定点对点关系,它将在应用层进行,因为UDP(如果我没记错的话)没有实现这个概念。@JohnPeters很抱歉造成混淆。我不会两次收到相同的消息。我在同一个接收器上接收两条消息,而我希望一个接收器接收一条消息,另一个接收器接收另一条消息。如果UDP更像广播,那么C#“SendTo”方法是谎言吗?@JohnPeters,我认为使用UDP在特定端口上监听是可能的。
using System;
using System.Net;
using System.Text;
using System.Net.Sockets;
using System.Collections.Generic;

namespace TestAsyncSockets {
    static class CProgramSuccinct {
        // Class for async receives
        class State {
            public Socket S;
            public EndPoint E;
            public byte[] Buffer;
        }

        private static readonly IPAddress s_LocalHost = new IPAddress(new byte[] {127, 0, 0, 1});
        private static readonly StringBuilder s_Logger = new StringBuilder();
        private static readonly object s_Locker = new object();

        static void Main() {
            System.IO.File.WriteAllText("C:\\log.txt", "");
            SetupReceivers();
            SendCommands();

            // Wait for messages to be received (hack for test code only)
            System.Threading.Thread.Sleep(1000);
            System.IO.File.AppendAllText("C:\\log.txt", s_Logger.ToString());
            Console.WriteLine(s_Logger.ToString());
            Console.ReadLine();
        }

        private static void SendCommands() {
            List<Tuple<IPEndPoint, IPEndPoint>> endpointPairs = new List<Tuple<IPEndPoint, IPEndPoint>> {
                new Tuple<IPEndPoint, IPEndPoint>(
                    new IPEndPoint(s_LocalHost, 50002), new IPEndPoint(s_LocalHost, 50000)), // client sends command from 50002 to 50000
                new Tuple<IPEndPoint, IPEndPoint>(
                    new IPEndPoint(s_LocalHost, 50001), new IPEndPoint(s_LocalHost, 50002)), // server sends command from 50001 to 50002
            };

            foreach (Tuple<IPEndPoint, IPEndPoint> endpoints in endpointPairs) {
                Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                sender.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                sender.Bind(endpoints.Item1);

                sender.SendTo(Encoding.ASCII.GetBytes("Command"), endpoints.Item2);
                System.Threading.Thread.Sleep(500);
                LogStatement("Sent Command from " + endpoints.Item1 + " to " + endpoints.Item2);
            }
        }

        private static void SetupReceivers() {
            List<Tuple<IPEndPoint, IPEndPoint>> endpointPairs = new List<Tuple<IPEndPoint, IPEndPoint>> {
                new Tuple<IPEndPoint, IPEndPoint>(
                    new IPEndPoint(s_LocalHost, 50000), new IPEndPoint(IPAddress.Any, 0)), // server receives commands on 50000 from anywhere
                new Tuple<IPEndPoint, IPEndPoint>(
                    new IPEndPoint(s_LocalHost, 50002), new IPEndPoint(s_LocalHost, 50000)), // client receives responses on 50002 from 50000
                new Tuple<IPEndPoint, IPEndPoint>(
                    new IPEndPoint(s_LocalHost, 50002), new IPEndPoint(s_LocalHost, 50001)), // client receives commands on 50002 from 50001
            };

            // Callbacks for each async receive
            List<AsyncCallback> receiverCallbacks = new List<AsyncCallback> { ServerCommandReceived, ClientResponseReceived, ClientCommandReceived };

            int i = 0;
            foreach (Tuple<IPEndPoint, IPEndPoint> endPoints in endpointPairs) {
                Socket receiver = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                receiver.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                receiver.Bind(endPoints.Item1);

                State receiveState = new State { S = receiver, E = endPoints.Item2, Buffer = new byte[100] };

                receiver.BeginReceiveFrom(receiveState.Buffer, 0, 100, SocketFlags.None, ref receiveState.E, receiverCallbacks[i], receiveState);
                LogStatement("Receiving on " + endPoints.Item1 + " from " + endPoints.Item2 + " and will call " + receiverCallbacks[i].Method.Name);
                i++;
            }
        }

        private static void ServerCommandReceived(IAsyncResult ar) {
            State state = LogMessage(ar, "ServerCommandReceived");

            // We just received a command. Send a response back to the port that sent the command (state.E)
            state.S.SendTo(Encoding.ASCII.GetBytes("Response"), state.E);
            LogStatement("ServerCommandReceived: Sent " + "Response" + " from " + state.S.LocalEndPoint + " to " + state.E);
            state.S.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.E, ServerCommandReceived, state);
        }

        // The client doesn't send responses
        private static void ClientResponseReceived(IAsyncResult ar) { LogMessage(ar, "ClientResponseReceived"); }
        private static void ClientCommandReceived(IAsyncResult ar) { LogMessage(ar, "ClientCommandReceived"); }

        // logs received message
        private static State LogMessage(IAsyncResult ar, string methodName) {
            System.Threading.Thread.Sleep(500);
            State state = (State)ar.AsyncState;
            int bytes = state.S.EndReceiveFrom(ar, ref state.E);
            if (bytes > 0)
            {
                byte[] actualMessage = new byte[bytes];
                Buffer.BlockCopy(state.Buffer, 0, actualMessage, 0, bytes);
                string message = string.Join("", Encoding.ASCII.GetChars(actualMessage));
                LogStatement(methodName + ": Received " + message + " on " + state.S.LocalEndPoint + " from " + state.E);
            }

            state.S.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.E, ClientCommandReceived, state);
            return state;
        }

        private static void LogStatement(string s) {
            lock (s_Locker) {
                s_Logger.AppendLine(s);
            }
        }
    }
}
Receiving on 127.0.0.1:50000 from 0.0.0.0:0 and will call ServerCommandReceived
Receiving on 127.0.0.1:50002 from 127.0.0.1:50000 and will call ClientResponseReceived
Receiving on 127.0.0.1:50002 from 127.0.0.1:50001 and will call ClientCommandReceived
Sent Command from 127.0.0.1:50002 to 127.0.0.1:50000
ServerCommandReceived: Received Command on 127.0.0.1:50000 from 127.0.0.1:50002
ServerCommandReceived: Sent Response from 127.0.0.1:50000 to 127.0.0.1:50002
Sent Command from 127.0.0.1:50001 to 127.0.0.1:50002
ClientResponseReceived: Received Command on 127.0.0.1:50002 from 127.0.0.1:50001
ClientCommandReceived: Received Response on 127.0.0.1:50002 from 127.0.0.1:50000