Mohamed Nuur

I am having a problem with using Socket.Recieve to recieve HTTP response. On one hand, recieve works for 95% of the pages that I need to download. I am using the Socket.Available property to check whether or not data is available before I call Socket.Recieve but sometimes Available returns 0 when there is data available. And since Recieve is blocking, I dont really have a way to know when the data is complete or not.

Here's an example code:

do

{

bytesRead = mServerSocket.Receive(bytesReceived, bytesReceived.Length, SocketFlags.None);

recieveBuffer.Append(Encoding.UTF8.GetString(bytesReceived, 0, bytesRead));

// only sleep if we ran out of data to recieve

if (mServerSocket.Available < recieveBuffer.Length)

{

System.Threading.Thread.Sleep(350);

}

}

while (mServerSocket.Available > 0);

Thanks,
Mohamed



Re: .NET Framework Networking and Communication Socket.Recieve Problem

Lucian Bargaoanu

The server should signal that there is no more data to receive by closing the socket.

If you are using a connection-oriented Socket, the Receive method will read as much data as is available, up to the size of the buffer. If the remote host shuts down the Socket connection with the Shutdown method, and all available data has been received, the Receive method will complete immediately and return zero bytes.





Re: .NET Framework Networking and Communication Socket.Recieve Problem

Mohamed Nuur

The server was not closing the connection for some reason, even after adding a header: "Connection: close" and "Proxy-Connection: close". I solved this problem by using a combination of asynchronous and synchronous calls. My receive function calls BeginRecieve and waits on a ManualEvent to signal the completion of the recieve or timeout.

The code looks something like this:

private struct StateObject

{

public static readonly int DefBufferSize = 8192;

public Socket socket;

public byte[] buffer;

public StringBuilder readSB;

public ManualResetEvent doneEvent;

public StateObject(Socket sock)

{

this.socket = sock;

this.buffer = new byte[DefBufferSize];

this.readSB = new StringBuilder(DefBufferSize);

this.doneEvent = new ManualResetEvent(false);

}

}

private string RecieveData()

{

// create the state object

StateObject state = new StateObject(mServerSocket);

// begin asynchrnously receiving data

mServerSocket.BeginReceive(state.buffer,

0,

StateObject.DefBufferSize,

0,

new AsyncCallback(this.OnReceiveSocketData),

state);

// compute the time out and wait that long for the data (2mins max)

if (state.doneEvent.WaitOne(120000, false))

{

// get the response into a string

string response = state.readSB.ToString();

// process the response

// [...]

}

else

{

// a timeout has occurred

// (you can still process what you have so far)

}

return state.readSB.ToString();

}

private void OnReceiveSocketData(IAsyncResult ar)

{

try

{

// retrieve the state object and the client socket

// from the asynchronous state object

StateObject state = (StateObject)ar.AsyncState;

// read data from the remote device

int bytesRead = state.socket.EndReceive(ar);

if (bytesRead > 0)

{

// get the response

string response = Encoding.UTF8.GetString(

state.buffer,

0,

bytesRead);

// there might be more data,

// so store the data received so far

state.readSB.Append(response);

// check if this response is a HTTP 100/Continue

if (IsContinueResponse(response))

{

// this is a 100/continue response...

// signal the completion

state.doneEvent.Set();

}

else

{

// get the rest of the data

state.socket.BeginReceive(state.buffer,

0,

StateObject.DefBufferSize,

0,

new AsyncCallback(this.OnReceiveSocketData),

state);

}

}

else

{

// we must be done... signal the completion

state.doneEvent.Set();

}

}

catch (Exception e)

{

}

}

Thanks for the help! I hope this helps anyone else that is facing the same problem.





Re: .NET Framework Networking and Communication Socket.Recieve Problem

Mike Flasko

Is this .Net 1.1 or 2.0   if 2.0 use the HttpListener class - you can receive HTTP requests with only a few lines of code. 

 

If you really want to do this with sockets .....

For blocking receives you will need to call receive until 0 bytes is returned.  Once 0 is returned the other side has closed the conneciton.  Keep in mind that HTTP supports keep alives and pipelining so you may need to do something more involved than waiting for a closed connection (ie. parse the headers and determine what socket action to take based on the headers)

To addresss your post above, the server does not close the connection in HTTP 1.1 as 1.1 supports keep-alive by default.  That is, the TCP connection remains connected even after the reponse is returned.






Re: .NET Framework Networking and Communication Socket.Recieve Problem

K.Z.Y.H

Mohamed Nuur wrote:

The server was not closing the connection for some reason, even after adding a header: "Connection: close" and "Proxy-Connection: close". I solved this problem by using a combination of asynchronous and synchronous calls. My receive function calls BeginRecieve and waits on a ManualEvent to signal the completion of the recieve or timeout.

The code looks something like this:

private struct StateObject

{

public static readonly int DefBufferSize = 8192;

public Socket socket;

public byte[] buffer;

public StringBuilder readSB;

public ManualResetEvent doneEvent;

public StateObject(Socket sock)

{

this.socket = sock;

this.buffer = new byte[DefBufferSize];

this.readSB = new StringBuilder(DefBufferSize);

this.doneEvent = new ManualResetEvent(false);

}

}

private string RecieveData()

{

// create the state object

StateObject state = new StateObject(mServerSocket);

// begin asynchrnously receiving data

mServerSocket.BeginReceive(state.buffer,

0,

StateObject.DefBufferSize,

0,

new AsyncCallback(this.OnReceiveSocketData),

state);

// compute the time out and wait that long for the data (2mins max)

if (state.doneEvent.WaitOne(120000, false))

{

// get the response into a string

string response = state.readSB.ToString();

// process the response

// [...]

}

else

{

// a timeout has occurred

// (you can still process what you have so far)

}

return state.readSB.ToString();

}

private void OnReceiveSocketData(IAsyncResult ar)

{

try

{

// retrieve the state object and the client socket

// from the asynchronous state object

StateObject state = (StateObject)ar.AsyncState;

// read data from the remote device

int bytesRead = state.socket.EndReceive(ar);

if (bytesRead > 0)

{

// get the response

string response = Encoding.UTF8.GetString(

state.buffer,

0,

bytesRead);

// there might be more data,

// so store the data received so far

state.readSB.Append(response);

// check if this response is a HTTP 100/Continue

if (IsContinueResponse(response))

{

// this is a 100/continue response...

// signal the completion

state.doneEvent.Set();

}

else

{

// get the rest of the data

state.socket.BeginReceive(state.buffer,

0,

StateObject.DefBufferSize,

0,

new AsyncCallback(this.OnReceiveSocketData),

state);

}

}

else

{

// we must be done... signal the completion

state.doneEvent.Set();

}

}

catch (Exception e)

{

}

}

Thanks for the help! I hope this helps anyone else that is facing the same problem.

This showed me how to implement ReceiveTimeout in asynchronous method.