Async Socket IO

P

Pete Davis

I'm writing an Nntp library and I've run into a problem that I've run into
before with async sockets. I fixed it before, but I don't remember how and
I'm running out of ideas this time.

My receive code is below. My question follows:

private NntpStatusResponse ReceiveData(CallbackType callbackType)
{

SocketState state = new SocketState();
// Receive the first block
_receiveEvent.Reset();
_nntpClient.BeginReceive(state.TempBuffer, 0, state.TempBuffer.Length,
SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
_receiveEvent.WaitOne();

if (null != state.Response)
{
return state.Response;
}
throw new NntpException("ReceiveData failed without a response");
}

private void ReceiveCallback(IAsyncResult asyncResult)
{
SocketState state = (SocketState) asyncResult.AsyncState;

int bytesReceived = _nntpClient.EndReceive(asyncResult);

if (!state.StatusReceived)
{
if (bytesReceived < 3)
{
throw new NntpException("Invalid response from server");
}
string strBuffer = Encoding.Default.GetString(state.TempBuffer, 0,
bytesReceived);
int statusCode = Convert.ToInt32(strBuffer.ToString().Substring(0,3));
int lineBreak = strBuffer.IndexOf(NNTPNewLine);
string statusText = strBuffer.Substring(3, strBuffer.Length - 3);
statusText = statusText.Trim();
if (lineBreak >= 0)
{
lineBreak += NNTPNewLine.Length;
strBuffer = strBuffer.Substring(lineBreak, strBuffer.Length -
lineBreak);
state.ResultBuffer.Append(strBuffer);
state.Response = new NntpStatusResponse(statusCode, statusText, null);
}

}
else
{
if (0 != bytesReceived)
{
string strBuffer = Encoding.Default.GetString(state.TempBuffer, 0,
bytesReceived);
state.ResultBuffer.Append(strBuffer);
}
}
if (bytesReceived < BufferSize)
{
string[] responseArray =
state.ResultBuffer.ToString().Split(NNTPNewLine.ToCharArray());
if (responseArray.Length > 1)
{
string newResponseStr = responseArray[responseArray.Length - 1];
state.Response = new NntpStatusResponse(state.Response.StatusCode,
state.Response.StatusText, responseArray);
}
}
else
{
_nntpClient.BeginReceive(state.TempBuffer, 0, state.TempBuffer.Length,
SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
}
_receiveEvent.Set();
}


The code blocks on the second receive at the EndReceive() call.

The first time through, it works perfectly. According the Ethereal, the
second message arrives, but the socket blocks on the EndReceive for the
second message, so I can't process it.

I believe my ManualResetEvent is set up correctly. Why would EndReceive()
block?

Thanks.

Pete
 
P

Pete Davis

Actually, this doesn't appear to be an async problem. I did a blocking
version, and my second time around calling Receive() blocks permanently as
well.

Also, I was mistaken. The async version blocks on BeginReceive() the second
time around, not EndReceive().

Any ideas?

Pete

--
http://www.petedavis.net
Pete Davis said:
I'm writing an Nntp library and I've run into a problem that I've run into
before with async sockets. I fixed it before, but I don't remember how and
I'm running out of ideas this time.

My receive code is below. My question follows:

private NntpStatusResponse ReceiveData(CallbackType callbackType)
{

SocketState state = new SocketState();
// Receive the first block
_receiveEvent.Reset();
_nntpClient.BeginReceive(state.TempBuffer, 0, state.TempBuffer.Length,
SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
_receiveEvent.WaitOne();

if (null != state.Response)
{
return state.Response;
}
throw new NntpException("ReceiveData failed without a response");
}

private void ReceiveCallback(IAsyncResult asyncResult)
{
SocketState state = (SocketState) asyncResult.AsyncState;

int bytesReceived = _nntpClient.EndReceive(asyncResult);

if (!state.StatusReceived)
{
if (bytesReceived < 3)
{
throw new NntpException("Invalid response from server");
}
string strBuffer = Encoding.Default.GetString(state.TempBuffer, 0,
bytesReceived);
int statusCode = Convert.ToInt32(strBuffer.ToString().Substring(0,3));
int lineBreak = strBuffer.IndexOf(NNTPNewLine);
string statusText = strBuffer.Substring(3, strBuffer.Length - 3);
statusText = statusText.Trim();
if (lineBreak >= 0)
{
lineBreak += NNTPNewLine.Length;
strBuffer = strBuffer.Substring(lineBreak, strBuffer.Length -
lineBreak);
state.ResultBuffer.Append(strBuffer);
state.Response = new NntpStatusResponse(statusCode, statusText, null);
}

}
else
{
if (0 != bytesReceived)
{
string strBuffer = Encoding.Default.GetString(state.TempBuffer, 0,
bytesReceived);
state.ResultBuffer.Append(strBuffer);
}
}
if (bytesReceived < BufferSize)
{
string[] responseArray =
state.ResultBuffer.ToString().Split(NNTPNewLine.ToCharArray());
if (responseArray.Length > 1)
{
string newResponseStr = responseArray[responseArray.Length - 1];
state.Response = new NntpStatusResponse(state.Response.StatusCode,
state.Response.StatusText, responseArray);
}
}
else
{
_nntpClient.BeginReceive(state.TempBuffer, 0, state.TempBuffer.Length,
SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
}
_receiveEvent.Set();
}


The code blocks on the second receive at the EndReceive() call.

The first time through, it works perfectly. According the Ethereal, the
second message arrives, but the socket blocks on the EndReceive for the
second message, so I can't process it.

I believe my ManualResetEvent is set up correctly. Why would EndReceive()
block?

Thanks.

Pete
 
P

Pete Davis

I found the problem. I got confused on the server responding. The server
sent an Ack, but not a response. It didn't send a response because my
command didn't terminate properly (CRLF). Duh.

Pete

--
http://www.petedavis.net
Pete Davis said:
Actually, this doesn't appear to be an async problem. I did a blocking
version, and my second time around calling Receive() blocks permanently as
well.

Also, I was mistaken. The async version blocks on BeginReceive() the second
time around, not EndReceive().

Any ideas?

Pete

--
http://www.petedavis.net
Pete Davis said:
I'm writing an Nntp library and I've run into a problem that I've run into
before with async sockets. I fixed it before, but I don't remember how and
I'm running out of ideas this time.

My receive code is below. My question follows:

private NntpStatusResponse ReceiveData(CallbackType callbackType)
{

SocketState state = new SocketState();
// Receive the first block
_receiveEvent.Reset();
_nntpClient.BeginReceive(state.TempBuffer, 0, state.TempBuffer.Length,
SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
_receiveEvent.WaitOne();

if (null != state.Response)
{
return state.Response;
}
throw new NntpException("ReceiveData failed without a response");
}

private void ReceiveCallback(IAsyncResult asyncResult)
{
SocketState state = (SocketState) asyncResult.AsyncState;

int bytesReceived = _nntpClient.EndReceive(asyncResult);

if (!state.StatusReceived)
{
if (bytesReceived < 3)
{
throw new NntpException("Invalid response from server");
}
string strBuffer = Encoding.Default.GetString(state.TempBuffer, 0,
bytesReceived);
int statusCode = Convert.ToInt32(strBuffer.ToString().Substring(0,3));
int lineBreak = strBuffer.IndexOf(NNTPNewLine);
string statusText = strBuffer.Substring(3, strBuffer.Length - 3);
statusText = statusText.Trim();
if (lineBreak >= 0)
{
lineBreak += NNTPNewLine.Length;
strBuffer = strBuffer.Substring(lineBreak, strBuffer.Length -
lineBreak);
state.ResultBuffer.Append(strBuffer);
state.Response = new NntpStatusResponse(statusCode, statusText, null);
}

}
else
{
if (0 != bytesReceived)
{
string strBuffer = Encoding.Default.GetString(state.TempBuffer, 0,
bytesReceived);
state.ResultBuffer.Append(strBuffer);
}
}
if (bytesReceived < BufferSize)
{
string[] responseArray =
state.ResultBuffer.ToString().Split(NNTPNewLine.ToCharArray());
if (responseArray.Length > 1)
{
string newResponseStr = responseArray[responseArray.Length - 1];
state.Response = new NntpStatusResponse(state.Response.StatusCode,
state.Response.StatusText, responseArray);
}
}
else
{
_nntpClient.BeginReceive(state.TempBuffer, 0, state.TempBuffer.Length,
SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
}
_receiveEvent.Set();
}


The code blocks on the second receive at the EndReceive() call.

The first time through, it works perfectly. According the Ethereal, the
second message arrives, but the socket blocks on the EndReceive for the
second message, so I can't process it.

I believe my ManualResetEvent is set up correctly. Why would EndReceive()
block?

Thanks.

Pete
 
Top