C#异步服务器/客户端体系结构

C#异步服务器/客户端体系结构,c#,asynchronous,client,chat,C#,Asynchronous,Client,Chat,第一篇关于堆栈溢出的帖子 不管怎么说,我正试图在业余时间自学网络编程,但我遇到了一个无法解决的难题。在玩了几天的同步网络方法之后,我决定制作一个客户机/服务器程序,它可以: 处理多个并发连接 处理多个通信流 有真正的双向沟通 在更一般的层面上,我想制作一个聊天程序。到服务器的多个客户端连接可以单独发送和接收数据,没有问题……但也可以让服务器从每个客户端向其他客户端发送数据 现在我还没有达到我想要的程度,所以我来这里寻求一些指导。我似乎无法使我的循环正常工作,而且我确信这与代码的异步性质有关…

第一篇关于堆栈溢出的帖子

不管怎么说,我正试图在业余时间自学网络编程,但我遇到了一个无法解决的难题。在玩了几天的同步网络方法之后,我决定制作一个客户机/服务器程序,它可以:

  • 处理多个并发连接
  • 处理多个通信流
  • 有真正的双向沟通
在更一般的层面上,我想制作一个聊天程序。到服务器的多个客户端连接可以单独发送和接收数据,没有问题……但也可以让服务器从每个客户端向其他客户端发送数据

现在我还没有达到我想要的程度,所以我来这里寻求一些指导。我似乎无法使我的循环正常工作,而且我确信这与代码的异步性质有关……无论出于何种原因,我似乎无法找出哪里出了问题。以下是代码块的详细信息:

Server.cs

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];
    IPAddress ipAddress = System.Net.IPAddress.Loopback;
    IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 3000);

    // 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.
            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();
    return 0;
}
}
使用系统;
Net系统;
使用System.Net.Sockets;
使用系统文本;
使用系统线程;
//用于异步读取客户端数据的状态对象
公共类状态对象
{
//客户端套接字。
公共套接字工作组=null;
//接收缓冲区的大小。
public const int BufferSize=1024;
//接收缓冲区。
公共字节[]缓冲区=新字节[BufferSize];
//接收到的数据字符串。
公共StringBuilder sb=新StringBuilder();
}
公共类异步SocketListener
{
//线程信号。
public static ManualResetEvent allDone=新的ManualResetEvent(false);
公共异步SocketListener()
{
}
公共静态侦听()
{
//输入数据的数据缓冲区。
字节[]字节=新字节[1024];
//为套接字建立本地端点。
//计算机的DNS名称
//运行侦听器的是“host.contoso.com”。
//IPHostEntry ipHostInfo=Dns.Resolve(Dns.GetHostName());
//IPAddress IPAddress=ipHostInfo.AddressList[0];
IPAddress IPAddress=System.Net.IPAddress.Loopback;
IPEndPoint localEndPoint=新IPEndPoint(ipAddress,3000);
//创建TCP/IP套接字。
套接字侦听器=新套接字(AddressFamily.InterNetwork,
流,ProtocolType.Tcp);
//将套接字绑定到本地端点并侦听传入连接。
尝试
{
Bind(localEndPoint);
听,听(100);
while(true)
{
//将事件设置为非信号状态。
全部完成。重置();
//启动异步套接字以侦听连接。
Console.WriteLine(“等待连接…”);
listener.beginacept(
新建异步回调(AcceptCallback),
听众);
//等待连接完成后再继续。
全部完成。WaitOne();
}
}
捕获(例外e)
{
Console.WriteLine(如ToString());
}
Console.WriteLine(“\n按ENTER继续…”);
Console.Read();
}
公共静态无效接受回调(IAsyncResult ar)
{
//向主线程发出继续的信号。
allDone.Set();
//获取处理客户端请求的套接字。
套接字侦听器=(套接字)ar.AsyncState;
套接字处理程序=listener.EndAccept(ar);
//创建状态对象。
StateObject状态=新的StateObject();
state.workSocket=处理程序;
handler.BeginReceive(state.buffer,0,StateObject.BufferSize,0,
新的异步回调(ReadCallback),状态);
}
公共静态void ReadCallback(IAsyncResult ar)
{
String content=String.Empty;
//检索状态对象和处理程序套接字
//从异步状态对象。
StateObject状态=(StateObject)ar.AsyncState;
套接字处理程序=state.workSocket;
//从客户端套接字读取数据。
int bytesRead=handler.EndReceive(ar);
如果(字节读取>0)
{
//可能会有更多数据,因此请存储到目前为止收到的数据。
state.sb.Append(Encoding.ASCII.GetString(
state.buffer,0,bytesRead));
//检查文件结尾标记。如果不存在,请读取
//更多数据。
content=state.sb.ToString();
if(content.IndexOf(“”>-1)
{
//所有数据都已从数据库中读取
//客户端。在控制台上显示它。
WriteLine(“从套接字读取{0}字节。\n数据:{1}”,
内容、长度、内容);
//将数据回显到客户端。
发送(处理程序、内容);
}
其他的
{
//未收到所有数据。获取更多信息。
handler.BeginReceive(state.buffer,0,StateObject.BufferSize,0,
新的异步回调(ReadCallback),状态);
}
}
}
私有静态void发送(套接字处理程序、字符串数据)
{
//使用ASCII编码将字符串数据转换为字节数据。
byte[]byteData=Encoding.ASCII.GetBytes(数据);
//开始将数据发送到远程设备。
handler.BeginSend(byteData,0,byteData.Length,0,
新的异步回调(SendCallback),处理程序);
}
私有静态void SendCallback(IAsyncResult ar)
{
尝试
{
//从状态对象检索套接字。
套接字处理程序=(套接字)ar.AsyncState;
//完成将数据发送到远程设备。
int bytesSent=handler.EndSend(ar);
WriteLine(“发送{0}字节到客户端。”,bytesSent);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
捕获(例外e)
{
Console.WriteLine(如ToString());
}
}
公共静态int Main(字符串[]args)
{
惊人的倾听();
返回0;
}
}
Client.cs

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

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 Program
{
    public static ManualResetEvent connectDone = new ManualResetEvent(false);
    public static ManualResetEvent sendDone = new ManualResetEvent(false);
    public static ManualResetEvent receiveDone = new ManualResetEvent(false);

    public static void Connect(EndPoint remoteEP, Socket client)
    {
        client.BeginConnect(remoteEP,
            new AsyncCallback(ConnectCallback), client);

        connectDone.WaitOne();
    }
    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 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, SocketFlags.None,
            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());
        }
    }
    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);
        }
        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)
                {
                    string response = state.sb.ToString();
                    Console.WriteLine(response);
                }
                // Signal that all bytes have been received.
                receiveDone.Set();
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }
    static void Main(string[] args)
    {
        IPAddress ipAddress = System.Net.IPAddress.Loopback;
        IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 3000);
        Socket sock = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
        Connect(localEndPoint, sock);
        string packet;
        while (true)
        {
            packet = Console.ReadLine();
            packet += "<EOF>";
            Send(sock, packet);
            Receive(sock);
            connectDone.WaitOne();
        }
    }
}
使用系统;
Net系统;
使用System.Net.Sockets;
使用系统文本;
使用系统线程;
公共类状态对象
{
//客户端套接字。
公共套接字工作组=null;
//接收缓冲区的大小。
公共常数