Socket.Recieve Problem
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
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.