Click here to Skip to main content
15,867,906 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Dear .Net Developers, I need some help. I am developing network client-server applications using TCP/IP socket technique and C#. I need to distribute the data located in XML file from server application to several subscribers apps: console windows apps and web apps. I wrote server applications using asynchronous calls technique. Everything is working well, but I have problem: if i run a lot of client applications, some data is lost during distribution. I fill like it is TCP/IP buffer overload, because if i run more apps then more data lost, but i am using CallBack method and I'm checking the previous result of sending (I save the result in currentAsynchResult to check the delivery, but it's not working for me. Here is some code:
Method
C#
static void SendToAll(string _msg)
    {
        foreach (ClientInfo _client in clientList)
        {
            Data msgToSend = new Data();
            msgToSend.cmdCommand = Command.Message;

            if (_client.strName == "Bill")
            {
                try
                {
                    //Fill the info for the message to be send                       
                    msgToSend.strName = "Bill";
                    msgToSend.strMessage = _msg;
                    byte[] byteData = msgToSend.ToByte();

                    currentClient = _client;

                    //Send it to the client 
                    _client.socket.BeginSend(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnBroadcast), currentAsynchResult);
                }

                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }

CallBack method:
C#
static void OnBroadcast(IAsyncResult ar)
{
    if (ar == currentAsynchResult)
    {
        try
        {
            currentClient.socket.EndSend(ar);
        }

        catch (ObjectDisposedException)
        { }

        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}

Using foreach to send the data:
C#
static void StartDistributeXML()
   {
       XmlDocument doc = new XmlDocument();
       doc.Load("test.xml");

       foreach (XmlNode node in doc.DocumentElement.ChildNodes)
       {
           SendtToAll(node.Attributes["text"].InnerText);
       }
   }

My idea is: 1. to check the CallBack method (may be my example is not correct) 2. To write some buffer for sending. 3. to check the details about sending packet (packet size, packet type , etc) - but i do not know how to implement it. Could please suggest me the solution? I am able to provide more code if needed.
Posted
Updated 15-Feb-14 18:46pm
v4

1 solution

Lately I always use streams, but I see that you are using the socket.BeginSend.
If I am not wrong, the Send (and consequently the BeginSend) can send less bytes than requested. So, you ask it to send 100 bytes and, for "splitting" reasons, it only sends 50. It actually returns that it sent 50 instead of sending the rest so you can update your statistics (something that's missing on the Stream.Write method), but this also means that you should test for it.

So, in your callback method you should check if all the data was sent and, if not, you should send the remaining (in my example, the remaining 50 bytes of a 100 bytes buffer).

*Note: This issue exists in the synchronous and in the asynchronous methods. In the asynchronous one, it is the call to EndSend() that will give you the information of how many bytes were really sent.
 
Share this answer
 
v2
Comments
x0rn 16-Feb-14 2:47am    
I checked EndSend() method. It can return IAsyncResult and SocketError objects only, so i tried to count bytes manually in the OnCallBack method using this code: SendBytes += System.Text.Encoding.UTF8.GetByteCount(currentClient.socket.EndSend(ar, out errorCode).ToString()) and in the Send method, i have: byteData.Length, so i know the amount of bytes which I have to send. I checked the number of bytes and surprisingly I found that it equal every time, even in case of data lost. Also I found the Exception: "The IAsyncResult object was not returned from the corresponding asynchronous method on this class." occurred in CallBack method. So I am little bit confused of the way of checking the Async state and of counting the bytes. I guess, may be the way of using Streams would be more successful. What is the way of count bytes, check Async state using Socket ? Or better to use Streams?
Paulo Zemek 16-Feb-14 7:59am    
Are you sure that it returns that?
When I look: http://msdn.microsoft.com/en-us/library/5f6fk8ze(v=vs.110).aspx

I see that EndSend() receives an IAsyncResult, but it returns an int.
Also, if you try to build an string with the wrong number of bytes you can receive an exception.

And you don't need to use encoding.GetByteCount()... simply use the EndSend() result to know how many bytes it sent.
x0rn 16-Feb-14 9:03am    
I checked it. And now i am confused for Exception: "The IAsyncResult object was not returned from the corresponding asynchronous method on this class." I sent you email with some details to not flood here. I hope we will find the solution and post it to community.
Paulo Zemek 16-Feb-14 14:11pm    
I think that your biggest problem is this line:

if (ar == currentAsynchResult)


Actually, the ar is what's important. There's no real "currentAsyncResult" as if you send data to two or more clients, you actually have 2 or more IAsyncResults.

So, your code should be capable of dealing with more clients. And it is no surprise that the send size is always the same... if you are sending the same data to all clients, the size will be equal. You could actually create the message and get its bytes outside of the loop.

And maybe you should revise your method names, as the OnBroadcast is not a broadcast. The method that does the broadcast is the one called SendToAll. The OnBroadcast is actually the method that will be invoked when a message arrive a client (it is not important which, and even the order doesn't need to be the same as the order of the send calls).
x0rn 17-Feb-14 3:32am    
Should i compare ar from EndSend() with object state of BeginSend()? And if it is not equal run again BeginSend to resend data?

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