异步客户端/服务器通信 C#

Posted

技术标签:

【中文标题】异步客户端/服务器通信 C#【英文标题】:Async Client/Server Communication C# 【发布时间】:2012-12-04 09:54:42 【问题描述】:

我正在学习客户端/服务器编程,并且正在制作一个异步客户端/服务器聊天应用程序。

我可以将客户端连接到服务器并发送一条消息,但是我在将相同的消息(仅用于测试目的)发送回客户端时遇到了问题。任何帮助表示赞赏...

客户代码

byte[] dataBuffer = new byte[10];
    public AsyncCallback callBack;
    public Socket clientSocket;
    IAsyncResult ar;
    Random rnd=new Random();

private void btnSend_Click(object sender, RoutedEventArgs e)
    
        try
        
            Object objData = txtMessage.Text;
            byte[] byData = Encoding.ASCII.GetBytes(objData.ToString());
            if (clientSocket != null)
            
                clientSocket.Send(byData);
                lbxMessages.Items.Add(txtMessage.Text);
            
            txtMessage.Text = "";
            btnSend.IsEnabled = false;
        
        catch(SocketException se)
        
            MessageBox.Show(se.Message);
        
    

//SocketPacket CLASS
    public class SocketPacket
    
        public Socket thisSocket;
        public byte[] dataBuffer = new byte[10];//test no, prevous [1]
    

//METHODS
    private void WaitForData()
    
        try
        
            if (callBack == null)
            
                callBack = new AsyncCallback(OnDataReceived);
            
            SocketPacket sckPack = new SocketPacket();
            sckPack.thisSocket = clientSocket;
            ar = clientSocket.BeginReceive(sckPack.dataBuffer, 0, sckPack.dataBuffer.Length, SocketFlags.None, callBack, sckPack);

        
        catch(SocketException se)
        
            MessageBox.Show(se.Message);
        
    

    public void OnDataReceived(IAsyncResult ar)
    
        try
        
            SocketPacket sckID = (SocketPacket)ar.AsyncState;
            int iRx = sckID.thisSocket.EndReceive(ar);
            char[] chars = new char[iRx + 1];
            Decoder d = Encoding.UTF8.GetDecoder();
            int charLen = d.GetChars(sckID.dataBuffer, 0, iRx, chars, 0);
            String szData = new String(chars);
            this.Dispatcher.Invoke((Action)(() =>
            
                lbxMessages.Items.Add(txtMessage.Text + szData);
            ));
            WaitForData();
        
        catch (ObjectDisposedException)
        
            Debugger.Log(0, "1", "\n OnDataRecieved: Socket has been closed\n");
        
        catch(SocketException se)
        
            MessageBox.Show(se.Message);
        
    

服务器代码

private void OnClientConnect(IAsyncResult asyncResult)
    
        try
        
            workerSocket[clientCount] = listenSocket.EndAccept(asyncResult);
            WaitForData(workerSocket[clientCount]);
            ++clientCount;

            if (clientCount<4)//allow max 3 clients
            

                String str = String.Format("Client # 0 connected", clientCount);                   

                this.Dispatcher.Invoke((Action)(() =>
                
                    lbxMessages.Items.Add(str);
                    lblConnectionStatus.Content =clientCount + " Connected";
                ));

                listenSocket.BeginAccept(OnClientConnect, null);
            
        
        catch (ObjectDisposedException)
        
            System.Diagnostics.Debugger.Log(0, "1", "\n OnClientConnection: Socket has been closed\n");
        
        catch (SocketException se)
        
            MessageBox.Show(se.Message);
        
    

public class SocketPacket
    
        public Socket currentSocket;
        public byte[] dataBuffer = new byte[50];//allowing the 50 digist to be sent at once
    

    private void WaitForData(Socket socket)
    
        try
        
            if (workerCallBack == null)
            
                workerCallBack = OnDataReceived;
            
            SocketPacket sckPack = new SocketPacket();
            sckPack.currentSocket = socket;
            socket.BeginReceive(sckPack.dataBuffer, 0, sckPack.dataBuffer.Length, SocketFlags.None, workerCallBack, sckPack);
        
        catch(SocketException se)
        
            MessageBox.Show(se.Message);
        
    

    public void OnDataReceived(IAsyncResult asyncResult)
    
        try
        
            SocketPacket socketData = (SocketPacket)asyncResult.AsyncState;
            int iRx = 0;
            iRx = socketData.currentSocket.EndReceive(asyncResult);
            char[] chars = new char[iRx];
            Decoder decoder = Encoding.UTF8.GetDecoder();
            int charLen = decoder.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);
            String receivedData = new String(chars);

            this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => lbxMessages.Items.Add(receivedData)));

            //Does not work - does not send same message back to client
            //byte[] byData = Encoding.ASCII.GetBytes(receivedData);
            //if (listenSocket != null)
            //
            //    listenSocket.Send(byData);
            //

            WaitForData(socketData.currentSocket);


        
        catch (ObjectDisposedException)
        
            System.Diagnostics.Debugger.Log(0, "1", "\n OnDataRecieved: Socket has been closed\n");
        
        catch (SocketException se)
        
            MessageBox.Show(se.Message);
        
    

【问题讨论】:

当你说它不起作用时,你的意思是它根本没有发回任何东西,或者它发送了错误的数据?我注意到您使用了两种不同的编码,您使用 UTF8 解码数据和 ASCII 将其编码回字符串中的字节。 它不会发送任何东西。我收到一条消息说“无法建立连接,因为目标计算机主动拒绝它”。没有意识到我使用了两种不同的编码。我会改变的。 【参考方案1】:

您应该使用相同的套接字来发送和接收数据。你在 socketData.currentSocket 上调用 EndReceive,所以你也应该调用 socketData.currentSocket.Send。

在服务器端有两个套接字。一个用于“收听”,您在其上调用accept。客户端连接后,accept 调用会为该客户端连接创建一个套接字,然后您可以使用该套接字为该特定客户端发送和接收数据。

您不使用“侦听”套接字来发送/接收数据。它没有连接到特定的连接。它仅用作接受新客户端连接的一种方式。

见http://msdn.microsoft.com/en-us/library/fx6588te.aspx

【讨论】:

以上是关于异步客户端/服务器通信 C#的主要内容,如果未能解决你的问题,请参考以下文章

服务器-客户端之间的 IOCP 或 TASK 通信

C# Socket异步通信

如何实现服务端客户端异步通信

异步通信----WebSocket

在 C# 中获取套接字对象的流

C#里实现简单的异步TCP服务器