Home All Groups Group Topic Archive Search About

Problem with synchronous Socket

Author
9 Feb 2006 4:47 PM
billa
Hi,

I need to implement a socket server. I am using the following code to
read from the socket.


        private int Read(ref byte[] buffer)
        {
            if (sapRequest.WaitForRequestBytes(socket) == 0)
                return 0;

            int numBytes = socket.Available;

            int numReceived = 0;
            buffer = new byte[numBytes];
            if (numBytes > 0)
            {
                numReceived = socket.Receive(buffer, 0, numBytes,
SocketFlags.None);
            }

            if (numReceived < numBytes)
            {
                byte[] tempBuffer = new byte[numReceived];

                if (numReceived > 0)
                {
                    Buffer.BlockCopy(buffer, 0, tempBuffer, 0, numReceived);
                }

                buffer = tempBuffer;
            }

            DWLog.Write(DWLogLevel.Information,"Number of bytes received: " +
numReceived);

            return numReceived;
        }


As you can see I am also using a method called WaitForRequestBytes.
Here it is:

        public int WaitForRequestBytes(Socket socket)
        {
            int availBytes = 0;

            try
            {
                DWLog.Write(DWLogLevel.Information,"Socket.Available: " +
socket.Available);
                if (socket.Available == 0)
                {
                    // poll until there is data
                    // DWLog.Write(DWLogLevel.Information, "Waiting for
more data. Polling 100ms");
                    // socket.Poll(10000 /* 100ms */,
SelectMode.SelectRead);

                    DWLog.Write(DWLogLevel.Information, "Waiting for
more data. Polling 100ms");
                    socket.Poll(10000 /* 100ms */,
SelectMode.SelectRead);

                    if (socket.Available == 0 && socket.Connected)
                    {
                        DWLog.Write(DWLogLevel.Information,"Waiting for more data.
Polling 1s");
                        socket.Poll(100000 /* 1s */, SelectMode.SelectRead);
                        // DWLog.Write(DWLogLevel.Information, "Waiting
for more data. Polling 10sec");
                        // socket.Poll(10000000 /* 10sec */,
SelectMode.SelectRead);

                    }
                }

                availBytes = socket.Available;
                DWLog.Write(DWLogLevel.Information,"Bytes available: " +
availBytes);
            }
            catch
            {
            }

            return availBytes;
        }

My problem now is the following. The bytes don´t arrive continuously
from the client. Therefore I introduced the method WaitForRequestBytes
which polls for data. The polling does its job. The polling time is
just enough to give the client enough time to send more data.  Now this
approach proves to be a drawback on performance since the polling is
always executed even if there is no more data available from the
client.
For some reason and under certain circumstances socket.Available return
0 even when the client has not yet sent all its data.
Can anyone explain thsi behaviour to me?
Is there a reliable way to determine if all bytes where received from a
client?

I think asyncronous sockets are no solution for me, because I need
control the order of the processing of the sockets.

Thanks for your help.

Author
9 Feb 2006 6:18 PM
Vadym Stetsyak
Hello, billa!


b> My problem now is the following. The bytes don´t arrive continuously
b> from the client. Therefore I introduced the method WaitForRequestBytes
b> which polls for data.

Since you're using synchronous sockets it would be sufficient to call socket.Receive. This call will be
blocking, that is when data will be available Receive will return it you in amount specified by passed buffer.
No polling is needed.

b> The polling does its job. The polling time is just enough to give the
b> client enough time to send more data.  Now this approach proves to be a
b> drawback on performance since the polling is always executed even if
b> there is no more data available from the client.
b> For some reason and under certain circumstances socket.Available return
b> 0 even when the client has not yet sent all its data.

socket.Available == 0 means that there is no data that can be returned to you via Receive call.

b> Is there a reliable way to determine if all bytes where received from a
b> client?

You cannot detect if client will sent all the data.
The way how you can determine this either with the help of flags that are included in the data stream or
with connection shutdown.

b> I think asyncronous sockets are no solution for me, because I need
b> control the order of the processing of the sockets.

Do you receive data from different sockets?


--
Regards, Vadym Stetsyak
www: http://vadmyst.blogspot.com
Author
10 Feb 2006 7:57 AM
billa
Hi Vadym,

I have tried socket.Receive but the problem there was that it waited
for data until the client went in a timeout and that was definitely
even longer than the polling took.

To answer your question whether I am receiving data from differernt
sockets. I am creating a new socket for each request coming in and
handle that socket connection in a thread. I use the following code:

        public void Run()
        {
            try
            {
                Thread th = new Thread(new ThreadStart(StartListenThreaded));
                th.Start();

            }
            catch(System.Exception e)
            {
            }
        }


The StartListenThreaded method looks like this:

        private void StartListenThreaded()
        {
            IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
            IPEndPoint EndPoint = new IPEndPoint(IPAddress.Any, port);
            Socket ss = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);


            ss.Bind( EndPoint);
            ss.Listen(20);
            try
            {
                while(true)
                {
                    Socket sock = ss.Accept();
                    Connection con = new Connection(sock);

                    Thread t = new Thread(new ThreadStart(con.ProcessOneRequest));
                    t.IsBackground=true;
                    t.Priority=ThreadPriority.BelowNormal;
                    t.Start();
                }
            }
            catch (System.Exception e1)
            {
            }

        }

I thought this was a good and performant way to handle the sockets.
What do you think? What do you think about my statement from above
about the socket.Receive problem?

Thanks

billa
Author
10 Feb 2006 11:10 AM
Vadym Stetsyak
Hello, billa!

b> I have tried socket.Receive but the problem there was that it waited
b> for data until the client went in a timeout and that was definitely
b> even longer than the polling took.

Hmm, thats strange, if there is no data then Poll also will return 0 for specific timout.
The usage of Receive here can help you avoid polling for data. That is you'll receive data when it will be available.

b> I thought this was a good and performant way to handle the sockets.
b> What do you think?

The scalability of such server can be poor, imagine when you will have great number of incomming connections/requests.

take a look at

( http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/progthrepool.asp )
( http://msdn.microsoft.com/msdnmag/issues/05/08/HighPerformanceSockets/default.aspx )

b> What do you think about my statement from above about the socket.Receive
b> problem?

It depends, however in your case I think that it is better to block on Receive than Poll.
--
Regards, Vadym Stetsyak
www: http://vadmyst.blogspot.com
Author
10 Feb 2006 3:42 PM
billa
Hi again Vadym,

I guess I will try the thing with Receive. The problem with it is that
my client does not close the socket. This means that Receive will wait
for data a long time until the client times out.  How can I handle this
problem .
Do you also have a solution for this?

Thanks

billa
Author
10 Feb 2006 4:13 PM
Vadym Stetsyak
Hello, billa!

b> I guess I will try the thing with Receive. The problem with it is that
b> my client does not close the socket. This means that Receive will wait
b> for data a long time until the client times out.  How can I handle this
b> problem .

Use flags that will indicate the end if client message

b> Do you also have a solution for this?

Do you communicate with client using application ( your custom ) protocol?

Generally connection close is not required, however in this case the data passed to and from client is organized according to definite communication protocol. Client & server know the protocol and can communicate using it without closing connection and blockin. For instance, mail and news applications....

--
Regards, Vadym Stetsyak
www: http://vadmyst.blogspot.com
Author
13 Feb 2006 12:48 PM
billa
Hi Vadym,

That is another problem. I have no control on what the client sends.
Basically it sends HTTP requests. So I can not send any stop flags or
anything like that.
Can I set a timeout on the socket before I use the Receive method? The
socket Receive would then automatically timeout when no further data is
send by the client after a certain time. It something like that
possible?

Thanks billa.
Author
13 Feb 2006 3:22 PM
Vadym Stetsyak
Hello, billa!

Take a look at SocketOptionName.ReceiveTimeout.

--
Regards, Vadym Stetsyak
www: http://vadmyst.blogspot.com
Author
13 Feb 2006 3:43 PM
Vadym Stetsyak
Hello, billa!

b> That is another problem. I have no control on what the client sends.
b> Basically it sends HTTP requests. So I can not send any stop flags or
b> anything like that.

Why can't you use HttpWebRequest/HttpWebResponse model for your task?

--
Regards, Vadym Stetsyak
www: http://vadmyst.blogspot.com

AddThis Social Bookmark Button