Matthew Cox

Matthew Cox

  • NA
  • 1
  • 0

Asynchornous Sockets

Jan 10 2008 6:31 PM
Hey guys I'm having problems with some Asynchronous socketing that I have been trying. ...I don't want to post my entire code but I will try to put in what is necessary.

My problem is that I can't continue to send messages to my Server class and have them echo the message back to the Client more than ONE TIME.

I have gleaned some of my coding techniques through other examples so bear with my probable misinterpretation of their usage. :)

Here is the class that handles ANY data that is sent back to the Client:
public class Client
{
...
...
...
private static ManualResetEvent receiveDone =  new ManualResetEvent(false);

...
....

....
private void ListenForData()
        {
            while (true)
            {
                receiveDone.Reset();
                ReceiveData(clientSocket);
                receiveDone.WaitOne();
            }
        }

public void ReceiveData(Socket client)
        {
            try
            {
                StateObject stateObj = new StateObject();
                stateObj.WorkSocket = client;

                client.BeginReceive(stateObj.testBuff, SocketFlags.None,
                                    new AsyncCallback(ReceiveDataCallback),
                                    stateObj);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }


private void ReceiveDataCallback(IAsyncResult result)
        {
            StateObject stateObj = (StateObject)result.AsyncState;
            Socket handler = (Socket)stateObj.WorkSocket;

            int bytesRead = handler.EndReceive(result);
            string data = String.Empty;

            if (bytesRead > 0)
            {
                IList<ArraySegment<byte>> infoList = stateObj.testBuff;
               
                //A user defined class that contains a method I write which seperates the data into its respective components of message and userID.

                byte[][] temp = ConversionClass.generateByteArrays(infoList[0].Array);

                byte[] msgBuff = temp[0];
                byte[] clientBuff = temp[1];

                string msg = Encoding.ASCII.GetString(msgBuff);
                string Id = Encoding.ASCII.GetString(clientBuff);
                string date = DateTime.Now.ToString();

                data = date + ' ' + clientID + ": " + msg;
                stateObj.StringBuffer.Append(data);

                /*stateObj.StringBuffer.Append(Encoding.ASCII.GetString(
                                             stateObj.Buffer, 0, bytesRead));*/
                if (data.IndexOf(EOM) > -1)
                {
                    data = data.Trim(EOM.ToCharArray());
                    notifyMessageHandlerUsers(data);
                    //ReceiveData(clientSocket);
                    //I tried just unblocking the receiveDone thread but it didn't work so i tried just recalling the receive method. That also does not work after the first message is received.
                }
                else
                {
                    handler.BeginReceive(stateObj.testBuff, SocketFlags.None,
                                          new AsyncCallback(ReceiveDataCallback),
                                          stateObj);
                }
            }

          //supposidly this would unblock the thread that is currently running the ListenForData() methed. But it appears to not be working.
            receiveDone.Set();
        }

....
....
....
}

just a few notes about this method. It is the callback method that is assigned when data is passed back thorugh the socket connection to the server. I chose to use an IList for the parameters rather than just a plain old buffer because I wanted to seperate the data ... date, clientID, message, etc...  lol, but it just combines them all into one buffer anyways once they are received by the Server. So I use a 'End of Unit' (31) character to signify the seperation of data.

Example: (I know you can't just concatenate byte arrays like this but I'm in a hurry so bear with it ;) )
string message = "hello";
string id = "matt";

byte[] byteArray = Encoding.ASCII.GetBytes(message)  + 31 + Encoding.ASCII.GetBytes(id);

As you can see, when actually done correctly ;) there would be signified diffences between the message and the id.

Now just for clarification, the ListenForData() method is called after a connection is made with the server and it gets through the loop to the call ReceiveData() and then the thread is blocked.

How do I get the thread to resume running after a message is finished transmitting?

thanks !


p.s

in case anyone decides to ask I'll just post my StateObject class as well: it's rough right now because I'm still in the learning process so I don't want to clean up code till I'm sure of what I'm doing.

public class StateObject
    {
        public const int BufferSize = 1024;    // Size of receive buffer.
        private Socket workSocket;    // Client socket.
        public IList<ArraySegment<byte>> testBuff;
        private byte[] buffer;   // Receive buffer.
        private StringBuilder stringBuffer;//Received data String.
        private string id;    // Host or conversation ID
        private string timeStamp;

        public StateObject()
        {
            testBuff = new List<ArraySegment<byte>>(2);
            byte[] msgBuff = new byte[BufferSize];
            byte[] clientID = new byte[16];
            testBuff.Add(new ArraySegment<byte>(msgBuff));
            testBuff.Add(new ArraySegment<byte>(clientID));

            buffer = new byte[BufferSize];
            stringBuffer = new StringBuilder();
            id = String.Empty;
            timeStamp = DateTime.Now.ToString();
        }

     //nd all corresponding Properties for attributes
       ..
...
...
...

    }