Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C# socket
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)
 
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.
 
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 16-Oct-10 14:21pm
Edited 16-Oct-10 15:07pm
v2
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

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.
  Permalink  
v2
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

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 Frown | :( 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?
  Permalink  

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

  Print Answers RSS
0 Maciej Los 310
1 OriginalGriff 285
2 Afzaal Ahmad Zeeshan 200
3 Sergey Alexandrovich Kryukov 195
4 BillWoodruff 180
0 OriginalGriff 6,499
1 Sergey Alexandrovich Kryukov 6,048
2 DamithSL 5,193
3 Manas Bhardwaj 4,657
4 Maciej Los 4,120


Advertise | Privacy | Mobile
Web01 | 2.8.1411022.1 | Last Updated 18 Oct 2010
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100