Click here to Skip to main content
15,879,535 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
Hello,

I have written a char server and a chat client application. I have a little problem though;

I store the names of all connected chat clients in a list. When a new client connects, he will receive the list through a socket. The method that iterates and sends it over the socket looks like this;

(The '1' and '0' infront of the string is to determine what to do with it)

C#
public static void getClientList(int i)
        {
            foreach (String client in userList)
            {
                workerSocket[i].Send(Encoding.Unicode.GetBytes("1"+client));
            }
        }


It simply iterates through the list and sends the name (a string).


Now, the client will receive and read it. The problem is the client dosn't read fast enough -- meaning that sometimes multiple names arrive in the buffer before the client can read them all.

C#
public void receive(IAsyncResult asyn)
        {
            string msg = "";
            int readBytes = 0;
            StateObject state = (StateObject)asyn.AsyncState;
            readBytes = state.getWorkSocket().EndReceive(asyn);
            msg = Encoding.Unicode.GetString(state.getBuffer(), 0, readBytes);  // store the received string
            if (readBytes > 0)
            {
                if (msg[0] == '0')   // metadata: start of string is 0 = MESSAGE
                {
                    msg = msg.Remove(0, 1);
                    this.textbox_display.Text = this.textbox_display.Text + msg;
                    this.textbox_display.SelectionStart = this.textbox_display.TextLength;
                    this.textbox_display.ScrollToCaret();
                    state.getWorkSocket().BeginReceive(state.getBuffer(), 0, state.getBufferSize(), 0, new AsyncCallback(receive), state);
                }
                if (msg[0] == '1')   // metadata: start of string is 1 = client list update
                {
                    msg = msg.Remove(0, 1);
                    this.textbox_connected.Text = msg;
                    this.listbox_users.Items.Add(msg);
                    state.getWorkSocket().BeginReceive(state.getBuffer(), 0, state.getBufferSize(), 0, new AsyncCallback(receive), state);
                }
            }
            else {
                this.textbox_display.Text = this.textbox_display.Text + "*** Received 0 bytes? disconnect!";
            }

        }



How do I make the sender wait untill the receiver has read the sent string before sending a new one? I realise it might be hard since the sender divides the string into packets, so it's not a coherent sending -- I mean, it's a bytestream after all. But surely somehow it must be done?
Posted
Updated 16-Oct-10 14:07pm
v2

Have a look at the msdn sample here[^].

They have used a delegate called EndSend during sending of data.
This should be useful to you.

They are also using a ManualResetEvent event indicating that the send is done. The next message can be sent after the first one is received and this event is triggered.

Hopefully, these two socket constructs may help resolve your problem.
 
Share this answer
 
v2
Hello again,

I've looked at this, I still cannot get it to work. Here's the Sending part below;

//
        // send client list to user i 
        //
        public static void getClientList(int i)
        {
            BinaryFormatter bformatter = new BinaryFormatter();
            MemoryStream mem = new MemoryStream();
            foreach (String client in userList)
            {
                // finalize the PDU and send it
                PimpDU pdu = new PimpDU();
                pdu.setType("name");
                pdu.setFrom(client);
                pdu.setPayload(client);
                bformatter.Serialize(mem, pdu);
                workerSocket[i].BeginSend(mem.GetBuffer(), 0, mem.GetBuffer().Length, SocketFlags.None, new AsyncCallback(getClientListCallback), workerSocket[i]);
                getlistDone.WaitOne();
                // reset memory stream
                mem.Position = 0;
                mem.SetLength(0);

            }
        }
        //
        // finishes the getClientList function
        //
        public static void getClientListCallback(IAsyncResult ar)
        {
            Socket client = (Socket)ar.AsyncState;
            client.EndSend(ar);
            getlistDone.Set();
        }




And here's the receiving;

//
        // received data from server
        //
        public void receive(IAsyncResult asyn)
        {
            BinaryFormatter bformatter = new BinaryFormatter();
            MemoryStream mem = new MemoryStream();
            int readBytes = 0;   
            StateObject state = (StateObject)asyn.AsyncState;
            readBytes = state.getWorkSocket().EndReceive(asyn);

            mem.Write(state.getBuffer(), 0, readBytes);
            mem.Position = 0;
            PimpDU pdu = (PimpDU)bformatter.Deserialize(mem);
            if (readBytes > 0)
            {
                if (pdu.getType()=="message")   // the PDU contains a MESSAGE
                {
                    this.textbox_display.Text = this.textbox_display.Text + pdu.getFrom() + ": " + pdu.getPayload() + "\r\n";
                    this.textbox_display.SelectionStart = this.textbox_display.TextLength;
                    this.textbox_display.ScrollToCaret();
                    state.getWorkSocket().BeginReceive(state.getBuffer(), 0, state.getBufferSize(), 0, new AsyncCallback(receive), state);
                }
                if (pdu.getType()=="name")   // the PDU contains a name of a new client
                {
                    this.listbox_users.Items.Add(pdu.getFrom());
                    state.getWorkSocket().BeginReceive(state.getBuffer(), 0, state.getBufferSize(), 0, new AsyncCallback(receive), state);
                }
            }
            else {
                this.textbox_display.Text = this.textbox_display.Text + "*** Received 0 bytes?!";
            }
         
        }



I know it's alot of code sorry :( I can't get it to work though. When I send my list of strings using the getClientList function, some simply dissapear/aren't read.

1. When my receiving buffer gets more than one object(PDU), I take it only one object is retrieved from the buffer, and the other is thrown away? Is there any way to read the first object, see if there's more stuff in the buffer, and if so read more?

2. Did I do anything wrong with ManualResetEvent?
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900