【问题标题】:Asynchronous socket Server C#, how to get data from AsyncCallback异步套接字服务器 C#,如何从 AsyncCallback 获取数据
【发布时间】:2017-06-29 09:40:35
【问题描述】:

我一直在尝试学习使用异步套接字,我确信我的问题非常简单,但我一直很难找到解决方案。我将从 MSDN 上为Asynchronous ServerAsynchronous Client 提供的代码开始。我正在关注代码是如何工作的,除了一个大问题:如何将客户端发送回程序主函数的字符串?我看到字符串在ReadCallback() 函数中完全形成的位置。

问题是如何将字符串内容的内容返回到Main()?我放了一些 cmets 试图澄清我想要到达的地方。提前感谢您的帮助。

异步服务器:

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

// State object for reading client data asynchronously  
public class StateObject {  
    // Client  socket.  
    public Socket workSocket = null;  
    // Size of receive buffer.  
    public const int BufferSize = 1024;  
    // Receive buffer.  
    public byte[] buffer = new byte[BufferSize];  
// Received data string.  
    public StringBuilder sb = new StringBuilder();    
}  

public class AsynchronousSocketListener {  
    // Thread signal.  
    public static ManualResetEvent allDone = new ManualResetEvent(false);  

    public AsynchronousSocketListener() {  
    }  

    public static void StartListening() {  
        // Data buffer for incoming data.  
        byte[] bytes = new Byte[1024];  

        // Establish the local endpoint for the socket.  
        // The DNS name of the computer  
        // running the listener is "host.contoso.com".  
        IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());  
        IPAddress ipAddress = ipHostInfo.AddressList[0];  
        IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);  

        // Create a TCP/IP socket.  
        Socket listener = new Socket(AddressFamily.InterNetwork,  
            SocketType.Stream, ProtocolType.Tcp );  

        // Bind the socket to the local endpoint and listen for incoming connections.  
        try {  
            listener.Bind(localEndPoint);  
            listener.Listen(100);  

            while (true) {  
                // Set the event to nonsignaled state.  
                allDone.Reset();  

                // Start an asynchronous socket to listen for connections.  
                Console.WriteLine("Waiting for a connection...");  
                listener.BeginAccept(   
                    new AsyncCallback(AcceptCallback),  
                    listener );  

                // Wait until a connection is made before continuing.  
                allDone.WaitOne();  
            }  

        } catch (Exception e) {  
            Console.WriteLine(e.ToString());  
        }  

        Console.WriteLine("\nPress ENTER to continue...");  
        Console.Read();  

    }  

    public static void AcceptCallback(IAsyncResult ar) {  
        // Signal the main thread to continue.  
        allDone.Set();  

        // Get the socket that handles the client request.  
        Socket listener = (Socket) ar.AsyncState;  
        Socket handler = listener.EndAccept(ar);  

        // Create the state object.  
        StateObject state = new StateObject();  
        state.workSocket = handler;  
        handler.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,  
            new AsyncCallback(ReadCallback), state);  
    }  

    public static void ReadCallback(IAsyncResult ar) {  
        String content = String.Empty;  

        // Retrieve the state object and the handler socket  
        // from the asynchronous state object.  
        StateObject state = (StateObject) ar.AsyncState;  
        Socket handler = state.workSocket;  

        // Read data from the client socket.   
        int bytesRead = handler.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));  

            // Check for end-of-file tag. If it is not there, read   
            // more data.  
            content = state.sb.ToString();  
            if (content.IndexOf("<EOF>") > -1) {  
                // All the data has been read from the   
                // client. Display it on the console.  
                Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",  
                    content.Length, content );  
                // Echo the data back to the client. 
                // AT THIS POINT content SHOULD HAVE THE STRING SENT 
                Send(handler, content);  
            } else {  
                // Not all data received. Get more.  
                handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,  
                new AsyncCallback(ReadCallback), state);  
            }  
        }  
    }  

    private static void Send(Socket handler, 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.  
        handler.BeginSend(byteData, 0, byteData.Length, 0,  
            new AsyncCallback(SendCallback), handler);  
    }  

    private static void SendCallback(IAsyncResult ar) {  
        try {  
            // Retrieve the socket from the state object.  
            Socket handler = (Socket) ar.AsyncState;  

            // Complete sending the data to the remote device.  
            int bytesSent = handler.EndSend(ar);  
            Console.WriteLine("Sent {0} bytes to client.", bytesSent);  

            handler.Shutdown(SocketShutdown.Both);  
            handler.Close();  

        } catch (Exception e) {  
            Console.WriteLine(e.ToString());  
        }  
    }  

    public static int Main(String[] args) {  
        StartListening();  
        // I want to make string here that has the result from ReadCallback so I can then perform other logic on the string.
        return 0;  
    }  
} 

【问题讨论】:

  • 由于您的源和目标使用 String 数据类型,它用于 Unicode 字符集的 UTF-16 编码的文本,因此请考虑使用其中一种 Unicode 编码进行传输。 UTF-8 (Encoding.UTF8) 在流和文件中很常见。 UTF-16 (Encoding.Unicode) 对于内存中的文本很常见(.NET、Java、JavaScript 等)。否则,从 Unicode 转换 ????到 ASCII 可能是有损的。对于非 Unicode 编码,您可以使用 EncoderEncoderExceptionFallback

标签: .net sockets asynchronous tcp c#-2.0


【解决方案1】:

您的示例非常正确。你只需要等待输入。在 return 语句前加上Console.ReadLine();

public static int Main(String[] args) 
{  
    StartListening();  
    // I want to make string here that has the result from ReadCallback so I can then perform other logic on the string.

    Console.ReadLine();
    return 0;  
} 

如果你想打印出输入。在ReadCallback 方法中解码接收到的字节后,只需使用Console.WriteLine()

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));  

    // Check for end-of-file tag. If it is not there, read   
    // more data.  
    content = state.sb.ToString();  

    // print the stuff to the console
    Console.WriteLine(content);

如果您想拥有内容并对其进行处理,您可以将其声明为静态类变量,您将能够在 main 方法中访问它:

public class AsynchronousSocketListener 
{
    public static string content = "";


public static int Main(String[] args) 
{  
    StartListening();  
    // I want to make string here that has the result from ReadCallback so I can then perform other logic on the string.

    Console.ReadLine();

    // wait until the message has arrive and press enter to jump to this line
    Console.WriteLine("Now I can do what ever I want with the incoming message: " + content);
    // just to be able to read it one more time before the program ends ;)
    Console.ReadLine();
    return 0;  
} 

当然,您必须从ReadCallback 中删除声明。

您必须知道它是异步的,因此您必须等待消息到达。但是如果你在那里打印它,你可以在控制台中看到它。剩下的就看你了

【讨论】:

  • 我稍后会试一试,但谢谢你的想法。
  • 不客气。如果出现问题,只需发表评论。我第一次在 WinForms 项目中尝试了这种异步的东西。等待收到的消息更容易,因为它不会通过 main 运行并立即完成。一个好的做法是编写一个聊天程序。
猜你喜欢
  • 2016-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多