Reputation: 2541
I am trying to use Socket.BeginReceive(...) and Socket.EndReceive(...) as my UDP Packet Receiver client. It receives and processes packets as expected, however, when I wish to cancel and shutdown the socket, my implemented Close() function exits on Socket.EndReceive(...). I assume an exception was thrown on the thread but I cannot figure out how to catch the exception to see what the problem is. I have used Socket.EndReceive(...) before with the SocketError returning as Success. Here is a bit of code that shows how I'm using the socket.
Updated Code
void _startReceiving()
{
_buffer = new byte[Marshal.SizeOf(typeof(EthernetShare.Message))];
_receiveResult = _udpSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, messageProcessor, null);
}
private void messageProcessor(IAsyncResult result)
{
int packetSize = _udpSocket.EndReceive(result);
if (packetSize == _buffer.Length)
{
byte[] packet = _buffer;
IAsyncResult asyncResult = result;
_startReceiving();
OnMessageReceieved(_buffer.ToStruct<DataStreamingMessage>());
}
}
public void Stop()
{
_continue = false;
SocketError error;
try
{
int tmp = _udpSocket.EndReceive(_receiveResult, out error);
}
catch (Exception)
{
throw;
}
_udpSocket.Close();
}
Old Code
private Socket _udpSocket;
private byte[] _buffer;
private IAsyncResult _receiveResult;
void _startReceiving()
{
byte[] buffer = new byte[Marshal.SizeOf(typeof(EthernetShare.Message))];
_receiveResult = _udpSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, messageProcessor, null);
//_receiveResult = _udpSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, messageProcessor, _continue);
}
private void messageProcessor(IAsyncResult result)
{
//if ((bool)result.AsyncState && result.IsCompleted)
if (result.IsCompleted)
{
_buffer = new byte[Marshal.SizeOf(typeof (EthernetShare.Message))];
//_receiveResult = _udpSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, messageProcessor, _continue);
_receiveResult = _udpSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, messageProcessor, null);
}
}
public void Stop()
{
_continue = false;
SocketError error;
try
{
int tmp = _udpSocket.EndReceive(_receiveResult, out error);
}
catch (Exception)
{
throw;
}
_udpSocket.Close();
}
Upvotes: 3
Views: 3537
Reputation: 15150
Your use of APM (Asynchronous Programming Model) is wrong. See: http://msdn.microsoft.com/en-us/library/ms228963.aspx
Each call to BeginXXX should be matched with an EndXXX.
In pseudo code, it might look something like this:
private bool isClosed;
private Socket socket;
void BeginReceiveNextPacket(){
socket.BeginReceive(..., EndReceiveNextPacket);
}
void EndReceiveNextPacket(IAsyncResult result){
try{
// By making a call to EndReceive, we allow the socket to wrap up, close internal handles and raise any exceptions if they exist.
socket.EndReceive(result);
// Now make a new call to BeginReceive after we invoked the actual call to EndReceive.
BeginReceiveNextPacket();
}
catch(SocketClosedException) {
if (closed){
// We forcefully closed this socket. Therefore, this exception was expected and we can ignore it.
}
else{
throw; // Catch an unexpected exception.
}
}
}
void Stop(){
isClosed = true;
socekt.Close();
}
Upvotes: 4