c# - 异步 C# 服务器连续从多个套接字读取

标签 c# sockets networking

我正在使用此处的 MSDN 服务器示例

http://msdn.microsoft.com/en-us/library/fx6588te(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1

我的问题是这段代码只持续接受新客户。我希望它也能不断地从它接受的所有客户那里收到信息。此代码接受客户端,然后从他们那里接收一条消息,然后发送一条消息,仅此而已。我唯一能想到的就是将异步接收方法放在 while(true) 循环中,但这听起来不对。

我稍微更改了示例,但它仍然具有相同的基本功能。

public class AServer
{
    // Thread signal.
    public static ManualResetEvent allDone = new ManualResetEvent(false); 
    Socket listener;
    ArrayList clients;

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

        clients = new ArrayList();

        // Create a TCP/IP socket.
        listener = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
        listener.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, 0);
        listener.Bind(localEndPoint);
        listener.Listen(100);
    }

    public void ServerLoop(){
        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();
        }

    }

    public 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.
        ClientData state = new ClientData();
        state.workSocket = handler;
        clients.Add(state);

        handler.BeginReceive(state.buffer, 0, ClientData.BufferSize, 0,new AsyncCallback(ReadCallback), state);
        Console.WriteLine("we passed handler.BeginReceive");
    }

    public void ReadCallback(IAsyncResult ar)
    {
        // Retrieve the state object and the handler socket
        // from the asynchronous state object.
        ClientData data = (ClientData)ar.AsyncState;
        String buff = String.Empty;
        Socket handler = data.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.
            buff = Encoding.ASCII.GetString(data.buffer, 0, bytesRead);
            ParseBuffer(buff);
            Send(handler, "1");
        }
        if (bytesRead == 0) {
            CloseConnection(handler);
        }
    }

    private bool ParseBuffer(String buff) {
        Console.WriteLine(buff);
        switch (buff[0]) { 
            case '0':

                break;
            case '1':
                break;
        }

        return true;
    }

    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)
    {
        // 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);
    }

    private static void CloseConnection(Socket handler)
    {
        handler.Shutdown(SocketShutdown.Both);
        handler.Close();
    }
}

当然,我的主要方法只是依次调用构造函数和循环。 arraylist 是我试图解决这个问题的一些尝试的残余。

编辑

我一直在寻找 Select 在 C 中为我提供的同类功能,但显然 C# 可以对事件做同样的事情。

最佳答案

在您的 ReadCallback 中,您需要再次发布异步 Receive:

public void ReadCallback(IAsyncResult ar)
{
    // Retrieve the state object and the handler socket
    // from the asynchronous state object.
    ClientData data = (ClientData)ar.AsyncState;
    String buff = String.Empty;
    Socket handler = data.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.
        buff = Encoding.ASCII.GetString(data.buffer, 0, bytesRead);
        ParseBuffer(buff);
        Send(handler, "1");

        // Here, you need to Receive again
        handler.BeginReceive(state.buffer, 0, ClientData.BufferSize, 0,new AsyncCallback(ReadCallback), state);
    }
    if (bytesRead == 0) {
        CloseConnection(handler);
    }
}   

通过这种方式,您将在每个套接字上接收、发送、接收、发送、接收、发送等。您需要错误处理,并且适当的服务器需要处理不完整的消息,但这是一般的想法。

顺便说一句,同样你必须在你的接受回调中发布另一个异步接受:

public 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.
    ClientData state = new ClientData();
    state.workSocket = handler;
    clients.Add(state);

    handler.BeginReceive(state.buffer, 0, ClientData.BufferSize, 0,new AsyncCallback(ReadCallback), state);
    Console.WriteLine("we passed handler.BeginReceive");

    // Here, you must start a new accept:
    listener.BeginAccept(new AsyncCallback(AcceptCallback),listener);
}

关于c# - 异步 C# 服务器连续从多个套接字读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25479779/

相关文章:

python - 在 python 中验证对等点

c++ - 通过 C++ 套接字发送图像 (Linux)

android - 如何在 android 中为 tcp 套接字强制发送 RST 而不是 FIN

c# - 什么时候最好使用 false 作为 Response.Redirect 的第二个参数,什么时候不最好?

c# - 如何保存和恢复 `PrinterSettings` ?

c# - 团结/骑士: order of multiplication operations is inefficient?

java - 使用套接字通信托管 Java 服务器

flash - 使用 Flash 在本地托管游戏?

algorithm - 在 bellman-ford 算法中到底是什么导致计数到无穷大

c# - 无法跨 AppDomains 传递 GCHandle