C# Net内核中的异步服务器套接字-如何返回结果?

C# Net内核中的异步服务器套接字-如何返回结果?,c#,asynchronous,.net-core,tcp,tcpclient,C#,Asynchronous,.net Core,Tcp,Tcpclient,我需要通过TCP异步发送数据。它是字符串的集合ICollection 我搜索并找到了一个好的(见下文)。该示例似乎位于.netframework下,但我假设它也适用于.netcore 我在做什么: 我将代码重新定位为非静态类 我想发送一组字符串ICollection。我知道我可以重写它来发送main方法中的字符串集合。没问题 我希望收到每封邮件的回复,并对其进行处理。当前响应静态存储在private static String response=String.Empty中。我不希望它是静态的

我需要通过TCP异步发送数据。它是字符串的集合
ICollection

我搜索并找到了一个好的(见下文)。该示例似乎位于
.netframework
下,但我假设它也适用于
.netcore

我在做什么:

  • 我将代码重新定位为非静态类

  • 我想发送一组字符串
    ICollection
    。我知道我可以重写它来发送main方法中的字符串集合。没问题

  • 我希望收到每封邮件的回复,并对其进行处理。当前响应静态存储在
    private static String response=String.Empty中。我不希望它是静态的。我想要一个局部方法变量

  • 我的挑战从第3项开始。。如何返回只能从
    private static void ReceiveCallback(IAsyncResult ar)

    我认为将其更改为
    私有静态字符串ReceiveCallback(IAsyncResult ar)
    不起作用。如果是,我如何从
    client.BeginReceive(state.buffer,0,StateObject.BufferSize,0,new-AsyncCallback(ReceiveCallback),state)读取它

  • 我在一篇很老的帖子上悬赏了300分,因为我发现了一个类似的问题:。很高兴奖励在这里和那里回答问题的人

    另外一个问题是:是否建议打开TCP连接,发送多条消息,然后关闭它?或者为发送的每条消息打开TCP连接

    微软示例

    using System;  
    using System.Net;  
    using System.Net.Sockets;  
    using System.Threading;  
    using System.Text;  
      
    // State object for receiving data from remote device.  
    public class StateObject {  
        // Client socket.  
        public Socket workSocket = null;  
        // Size of receive buffer.  
        public const int BufferSize = 256;  
        // Receive buffer.  
        public byte[] buffer = new byte[BufferSize];  
        // Received data string.  
        public StringBuilder sb = new StringBuilder();  
    }  
      
    public class AsynchronousClient {  
        // The port number for the remote device.  
        private const int port = 11000;  
      
        // ManualResetEvent instances signal completion.  
        private static ManualResetEvent connectDone =
            new ManualResetEvent(false);  
        private static ManualResetEvent sendDone =
            new ManualResetEvent(false);  
        private static ManualResetEvent receiveDone =
            new ManualResetEvent(false);  
      
        // The response from the remote device.  <------ ### the response data that I want to access, non statically
        private static String response = String.Empty;  
      
        private static void StartClient() {  
            // Connect to a remote device.  
            try {  
                // Establish the remote endpoint for the socket.  
                // The name of the
                // remote device is "host.contoso.com".  
                IPHostEntry ipHostInfo = Dns.GetHostEntry("host.contoso.com");  
                IPAddress ipAddress = ipHostInfo.AddressList[0];  
                IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);  
      
                // Create a TCP/IP socket.  
                Socket client = new Socket(ipAddress.AddressFamily,  
                    SocketType.Stream, ProtocolType.Tcp);  
      
                // Connect to the remote endpoint.  
                client.BeginConnect( remoteEP,
                    new AsyncCallback(ConnectCallback), client);  
                connectDone.WaitOne();  
      
                // Send test data to the remote device.  
                Send(client,"This is a test<EOF>");  
                sendDone.WaitOne();  
      
                // Receive the response from the remote device.  
                Receive(client);  
                receiveDone.WaitOne();  
      
                // Write the response to the console.  
                Console.WriteLine("Response received : {0}", response);  
      
                // Release the socket.  
                client.Shutdown(SocketShutdown.Both);  
                client.Close();  
      
            } catch (Exception e) {  
                Console.WriteLine(e.ToString());  
            }  
        }  
      
        private static void ConnectCallback(IAsyncResult ar) {  
            try {  
                // Retrieve the socket from the state object.  
                Socket client = (Socket) ar.AsyncState;  
      
                // Complete the connection.  
                client.EndConnect(ar);  
      
                Console.WriteLine("Socket connected to {0}",  
                    client.RemoteEndPoint.ToString());  
      
                // Signal that the connection has been made.  
                connectDone.Set();  
            } catch (Exception e) {  
                Console.WriteLine(e.ToString());  
            }  
        }  
      
        private static void Receive(Socket client) {  
            try {  
                // Create the state object.  
                StateObject state = new StateObject();  
                state.workSocket = client;  
      
                // Begin receiving the data from the remote device.  
                client.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,  
                    new AsyncCallback(ReceiveCallback), state);  //<------ The receive callback is here, how do I return the result to the caller?
            } catch (Exception e) {  
                Console.WriteLine(e.ToString());  
            }  
        }  
      
        private static void ReceiveCallback( IAsyncResult ar ) {  
            try {  
                // Retrieve the state object and the client socket
                // from the asynchronous state object.  
                StateObject state = (StateObject) ar.AsyncState;  
                Socket client = state.workSocket;  
      
                // Read data from the remote device.  
                int bytesRead = client.EndReceive(ar);  
      
                if (bytesRead > 0) {  
                    // There might be more data, so store the data received so far.  
                state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead));  
      
                    // Get the rest of the data.  
                    client.BeginReceive(state.buffer,0,StateObject.BufferSize,0,  
                        new AsyncCallback(ReceiveCallback), state);  
                } else {  
                    // All the data has arrived; put it in response.  
                    if (state.sb.Length > 1) {  
                        response = state.sb.ToString();  //<--------- ### Where it is assigned, I want it returned
                    }  
                    // Signal that all bytes have been received.  
                    receiveDone.Set();  
                }  
            } catch (Exception e) {  
                Console.WriteLine(e.ToString());  
            }  
        }  
      
        private static void Send(Socket client, String data) {  
            // Convert the string data to byte data using ASCII encoding.  
            byte[] byteData = Encoding.ASCII.GetBytes(data);  
      
            // Begin sending the data to the remote device.  
            client.BeginSend(byteData, 0, byteData.Length, 0,  
                new AsyncCallback(SendCallback), client);  
        }  
      
        private static void SendCallback(IAsyncResult ar) {  
            try {  
                // Retrieve the socket from the state object.  
                Socket client = (Socket) ar.AsyncState;  
      
                // Complete sending the data to the remote device.  
                int bytesSent = client.EndSend(ar);  
                Console.WriteLine("Sent {0} bytes to server.", bytesSent);  
      
                // Signal that all bytes have been sent.  
                sendDone.Set();  
            } catch (Exception e) {  
                Console.WriteLine(e.ToString());  
            }  
        }  
      
        public static int Main(String[] args) {  
            StartClient();  
            return 0;  
        }  
    }
    
    使用系统;
    Net系统;
    使用System.Net.Sockets;
    使用系统线程;
    使用系统文本;
    //用于从远程设备接收数据的状态对象。
    公共类StateObject{
    //客户端套接字。
    公共套接字工作组=null;
    //接收缓冲区的大小。
    public const int BufferSize=256;
    //接收缓冲区。
    公共字节[]缓冲区=新字节[BufferSize];
    //接收到的数据字符串。
    公共StringBuilder sb=新StringBuilder();
    }  
    公共类异步客户端{
    //远程设备的端口号。
    专用常量int端口=11000;
    //ManualResetEvent实例信号完成。
    专用静态手动重置事件已完成=
    新手动重置事件(错误);
    私有静态手动重置事件sendDone=
    新手动重置事件(错误);
    私有静态手动重置事件接收完成=
    新手动重置事件(错误);
    //来自远程设备的响应。1){
    response=state.sb.ToString();//您可以创建一个类(非静态,我称之为AsynchronousClient),该类直接从Microsoft示例中实现套接字通信的所有逻辑。相关添加包括3个事件(更多信息):

    1) ConnectionComplete,异步连接操作完成时激发

    2) SendComplete,在成功发送数据(本例中为字符串)时激发

    3) DataReceived,当有来自远程端点的传入数据时激发

    基本上,该类公开了3个公共方法:AsyncConnect、AsyncSend和AsyncReceive。在3个私有回调上,会触发上面列表中的相应事件,并通知使用AsynchronousClient的类操作终止

    public class AsynchronousClient
    {
        /// <summary>
        /// The client's socket instance.
        /// </summary>
        private Socket _clientSocket;
    
        /// <summary>
        /// Define the signature of the handler of the ConnectionComplete event.
        /// </summary>
        public delegate void ConnectionCompleteEventDelegate(AsynchronousClient sender, Socket clientSocket);
    
        /// <summary>
        /// Define the signature of the handler of the SendComplete event.
        /// </summary>
        public delegate void SendCompleteEventDelegate(AsynchronousClient sender, Socket clientSocket);
    
        /// <summary>
        ///  Define the signature of the handler of the DataReceived event.
        /// </summary>
        public delegate void DataReceivedEventDelegate(AsynchronousClient sender, Socket clientSocket, string data);
    
        /// <summary>
        /// ConnectionComplete event the client class can subscribe to.
        /// </summary>
        public event ConnectionCompleteEventDelegate ConnectionComplete;
    
        /// <summary>
        /// SendComplete event a class using an AsynchronousClient instance can subscribe to.
        /// </summary>
        public event SendCompleteEventDelegate SendComplete;
    
        /// <summary>
        /// DataReceived event a class using an AsynchronousClient instance can subscribe to.
        /// </summary>
        public event DataReceivedEventDelegate DataReceived;
    
        /// <summary>
        /// The remote endpoint the socket is going to communicate to. 
        /// </summary>
        public IPEndPoint RemoteEndpoint { get; private set; }
    
        /// <summary>
        /// Class initializer.
        /// </summary>
        /// <param name="remoteEndpoint">The remote endpoint to connect to.</param>
        public AsynchronousClient(IPEndPoint remoteEndpoint)
        {
            RemoteEndpoint = remoteEndpoint;
            // Create a TCP/IP socket.  
            _clientSocket = new Socket(
                RemoteEndpoint.AddressFamily, 
                SocketType.Stream, 
                ProtocolType.Tcp);
        }
    
        /// <summary>
        /// Asynchronous connection request.
        /// </summary>
        public void AsyncConnect()
        {
            try
            {
                // Initiate the connection procedure to the remote endpoint.  
                _clientSocket.BeginConnect(
                    RemoteEndpoint,
                    new AsyncCallback(AsyncConnectCallback), _clientSocket);
            }
            catch (Exception ex)
            {
                // TODO: manage exception.
                throw;
            }
        }
    
        /// <summary>
        /// Called after the connection to the remote endpoint is established.
        /// </summary>
        private void AsyncConnectCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the socket from the state object.  
                Socket client = (Socket)ar.AsyncState;
                // Complete the connection.  
                client.EndConnect(ar);
                // If a client class is subscribed to the event, invoke the delegate.
                if (!(ConnectionComplete is null))
                    ConnectionComplete.Invoke(this, client);
            }
            catch (Exception ex)
            {
                // TODO: manage exception.
                throw;
            }
        }
    
        /// <summary>
        /// Asynchronously sends a string to the remote endpoint.
        /// </summary>
        public void AsyncSend(string data)
        {
            try
            {
                // Convert the string data to byte data using ASCII encoding.  
                byte[] byteData = Encoding.ASCII.GetBytes(data);
                // Begin sending the data to the remote device.  
                _clientSocket.BeginSend(byteData, 0, byteData.Length, 0,
                    new AsyncCallback(AsyncSendCallback), _clientSocket);
            }
            catch(Exception ex)
            {
                // TODO: manage exception.
                throw;
            }
        }
    
        /// <summary>
        /// Called after the send operation is complete.
        /// </summary>
        private void AsyncSendCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the socket from the state object.  
                Socket client = (Socket)ar.AsyncState;
                // Complete sending the data to the remote device.  
                int bytesSent = client.EndSend(ar);
                // If a client class is subscribed to the event, invoke the delegate.
                if (!(SendComplete is null))
                    SendComplete(this, client);
            }
            catch (Exception ex)
            {
                // TODO: manage exception.
                throw;
            }
        }
    
        /// <summary>
        /// Asynchronously waits for a response from the remote endpoint.
        /// </summary>
        public void AsyncReceive(Socket client)
        {
            try
            {
                // Create the state object.  
                StateObject state = new StateObject();
                state.workSocket = client;
                // Begin receiving the data from the remote device.  
                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(AsyncReceiveCallback), state);
            }
            catch (Exception ex)
            {
                // TODO: manage exception.
                throw;
            }
        }
    
        /// <summary>
        /// Called after the receive operation is complete.
        /// </summary>
        private void AsyncReceiveCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the state object and the client socket
                // from the asynchronous state object.  
                StateObject state = (StateObject)ar.AsyncState;
                Socket client = state.workSocket;
                // Read data from the remote device.  
                int bytesRead = client.EndReceive(ar);
    
                if (bytesRead > 0)
                {
                    // There might be more data, so store the data received so far.  
                    state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
                    // Get the rest of the data.  
                    client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                        new AsyncCallback(AsyncReceiveCallback), state);
                }
                else
                {
                    // All the data has arrived; put it in response.  
                    if (state.sb.Length > 1)
                    {
                        var response = state.sb.ToString();  //<--------- ### Where it is assigned, I want it returned
                        // If a client class is subscribed to the event, invoke the delegate.
                        // Here the client class is notified, and the response is passed as parameter to the delegate.
                        if (!(DataReceived is null))
                            DataReceived.Invoke(this, client, response);
                    }
                }
            }
            catch (Exception ex)
            {
                // TODO: manage exception.
                throw;
            }
        }
    }
    
    公共类异步客户端
    {
    /// 
    ///客户端的套接字实例。
    /// 
    专用套接字_clientSocket;
    /// 
    ///定义ConnectionComplete事件处理程序的签名。
    /// 
    公共委托void ConnectionCompleteEventDelegate(异步客户端发送方、套接字客户端套接字);
    /// 
    ///定义SendComplete事件处理程序的签名。
    /// 
    公共委托void sendpleteeventdelegate(异步客户端发送方,套接字clientSocket);
    /// 
    ///定义DataReceived事件处理程序的签名。
    /// 
    公共委托void DataReceivedEventDelegate(异步客户端发送方、套接字客户端套接字、字符串数据);
    /// 
    ///客户端类可以订阅的ConnectionComplete事件。
    /// 
    公共事件连接完成甚至删除连接完成;
    /// 
    ///SendComplete事件使用AsynchronousClient实例的类可以订阅的事件。
    /// 
    公共事件SendCompleteEventDelegate SendComplete;
    /// 
    ///使用AsynchronousClient实例的类可以订阅的DataReceived事件。
    /// 
    公共事件DataReceivedEventDelegate DataReceived;
    /// 
    ///套接字要与之通信的远程端点。
    /// 
    公共IPEndPoint远程端点{get;private set;}
    /// 
    ///类初始值设定项。
    /// 
    ///要连接到的远程终结点。
    公共异步客户端(IPEndPoint remoteEndpoint)
    {
    RemoteEndpoint=RemoteEndpoint;
    //创建TCP/IP套接字。
    _clientSocket=新套接字(
    RemoteEndpoint.AddressFamily,
    SocketType.Stream,
    原型(Tcp);
    }
    /// 
    ///异步连接请求。
    /// 
    公共void异步连接()
    {
    尝试
    {
    //启动到远程端点的连接过程。
    _clientSocket.BeginConnect(
    远程端点,
    新的AsyncCallback(AsyncConnectCallback),\u clientSocket);
    }
    捕获(例外情况除外)
    {
    //TODO:管理异常。
    投掷;
    }
    }
    /// 
    ///在与远程端点的连接建立后调用。
    /// 
    专用void AsyncConnectCallback(IAsyncResult ar)
    {
    尝试
    {
    //从sta中检索套接字
    
            private AsynchronousClient _asyncClient;
    
            private void Form1_Load(object sender, EventArgs e)
            {
                // I'm testing on the loopback interface.
                var remoteIp = IPAddress.Parse("127.0.0.1");
    
                // Create a new remote endpoint.
                var remoteEndpoint = new IPEndPoint(remoteIp, 11000);
    
                // Create a new instance of the AsynchronousClient client, 
                // passing the remote endpoint as parameter.
                _asyncClient = new AsynchronousClient(remoteEndpoint);
    
                // Subscription to the ConnectionComplete event.
                _asyncClient.ConnectionComplete += AsyncClient_ConnectionComplete;
    
                // Subscription to the SendComplete event.
                _asyncClient.SendComplete += AsyncClient_SendComplete;
    
                // Subscription to the DataReceived event.
                _asyncClient.DataReceived += AsyncClient_DataReceived;
            }
    
            /// <summary>
            /// Handler of the DataReceived event.
            /// </summary>
            private void AsyncClient_DataReceived(AsynchronousClient sender, Socket clientSocket, string data)
            {
                // Here I manage the data received by the remote endpoint.
                MessageBox.Show(string.Format("Data received: {0}", data));
            }
    
            /// <summary>
            /// Handler of the SendComplete event.
            /// </summary>
            private void AsyncClient_SendComplete(AsynchronousClient sender, Socket clientSocket)
            {
                // Here I'm starting an async receive operation, as I expect the remote endpoint
                // to send back some data.
                _asyncClient.AsyncReceive(clientSocket);
            }
    
            /// <summary>
            /// Handler of the ConnectionComplete event.
            /// </summary>
            private void AsyncClient_ConnectionComplete(AsynchronousClient sender, Socket clientSocket)
            {
                // Here I just want to warn the user the connection is set.
                MessageBox.Show("Successfully connected to the remote endpoint.");
            }
    
            /// <summary>
            /// Handler of the connect button.
            /// </summary>
            private void BtnConnect_Click(object sender, EventArgs e)
            {
                _asyncClient.AsyncConnect();
            }
    
            /// <summary>
            /// Handler of the SendString button.
            /// </summary>
            private void BtnSendString_Click(object sender, EventArgs e)
            {
                _asyncClient.AsyncSend("TEST DATA<EOF>");
            }
    
    ICollection<string> strings = ...;
    using Socket socket = ...;
    using var stream = new NetworkStream(socket);
    using var writer = new StreamWriter(stream);
    
    foreach(string s in strings)
    {
        await writer.WriteLineAsync(s);
    }
    await writer.FlushAsync();