0

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);
        }
    }
Colin Roe
  • 774
  • 1
  • 18
  • 35
  • When you say it doesn't work do you mean that it's not sending anything back at all, or it's sending the wrong data? I notice you're using two different encodings, you're using UTF8 to decode the data and ASCII to encode it back into bytes from the string. – Sean Airey Dec 04 '12 at 10:02
  • It won't send anything. I get an message saying 'No connection could be made because the target machine actively refused it'. Didn't realise I was using two different encodings. I will change that. – Colin Roe Dec 04 '12 at 10:31

1 Answers1

0

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

Palo
  • 1,051
  • 8
  • 12