简体   繁体   中英

Async Client/Server Communication C#

I am learning about client/server programming and I am making an Asynchronous Client/Server Chat application.

I can connect the client to the server and send a message but I am having a problem sending the same message back (just for testing purposes) to the client. Any help appreciated...

CLIENT CODE

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

SERVER CODE

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

You should use the same socket for sending and receiving data. You call EndReceive on socketData.currentSocket so you should also call socketData.currentSocket.Send.

On the server side there are two sockets. One is used for "listening", and you call accept on it. Once a client connects, the accept call creates a socket for just for that client connection, which you then use for sending and receiving data for that particular client.

You don't use the "listening" socket for sending/receiving data. It's not hooked up to a particular connection. It's serves only as a way to accept new client connections.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM