Reputation: 753
from where this problem can be?
SocketException An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full
Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 50509);
EndPoint tmpRemote = (EndPoint)(sender);
newsock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
newsock.Bind(ipep);
while (thread_Listen == true && work == true)
{
try
{
Object state = new Object();
**>> at this place >>** newsock.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref tmpRemote, new AsyncCallback(DoReceiveFrom), state);
Array.Clear(buffer, 0, buffer.Length);
}
catch (SocketException ex)
{
MessageBox.Show(ex.ToString());
}
}
This how func DoReceiveFrom looks like
private void DoReceiveFrom(IAsyncResult iar)
{
try
{
Socket recvSock = (Socket)iar.AsyncState;
EndPoint clientEP = new IPEndPoint(IPAddress.Any, 0);
int msgLen = recvSock.EndReceiveFrom(iar, ref clientEP);
byte[] localMsg = GetAndCleanPacket(buffer);
string[] packet = Encoding.ASCII.GetString(localMsg).Split(new Char[] { '|' });
if (packet.Length > 0)
{
if (packet[0] == "ms")
{
// Connect
if (packet[1] == "c") MSc(ip[0], packet[9], packet, clientEP);
else if (packet[1] == "s") MSs(ip[0], packet);
else if (packet[1] == "d") MDc(ip[0], packet);
}
else if (packet[0] == "p") ping(clientEP);
else if (packet[0] == "sList") serverList(clientEP);
else if (packet[0] == "bi") brGetInfo(packet, clientEP);
else if (packet[0] == "error") AddError(packet[1], packet[2]);
}
}
catch (InvalidOperationException)
{
}
catch (SocketException)
{
}
catch (Exception e)
{
errors.Add(e.ToString());
}
}
Upvotes: 1
Views: 3121
Reputation: 313
What I do is use a "StateObject" class which contains an "IAsyncResult" object. This should be used for both TCP and UDP. Here is an example for UDP.
// Used for receiver to signal client that data has been received
// 'readonly' for .Net 4.8
private readonly ManualResetEvent receiveDone = new ManualResetEvent(false);
/// <summary>
/// Supports async receive on UDP socket
/// </summary>
private class StateObject
{
// Client socket.
public UdpClient workSocket = null;
// Receive buffer.
public byte[] buffer;
// Received data string.
public StringBuilder sb = new StringBuilder();
//public int bytesRead;
// receiver state
public IAsyncResult result;
public delegate void RecvMethod(IAsyncResult result);
public void BeginReceive(RecvMethod recvMethod, UdpClient udpClient)
{
// Set the socket
workSocket = udpClient;
// start async receiver
result = workSocket.BeginReceive(new AsyncCallback(recvMethod), this);
}
}
The "Receive" method (called by the client app) checks its state, and only fires if receiver has not signaled (using receiveDone) and IAsyncResult.Completed is false.
That is the key here: if receiver is still active, do not fire it again, otherwise you are wasting system resources. It takes another socket and buffer memory space, which will bite your application, usually when you're trying to communicate with a device that is off-line.
/// <summary>
/// Set up async receive handler
/// </summary>
/// <returns></returns>
public void Receive()
{
// if receiver running, no packet received - do not restart receiver!
// did receiver signal done?
if (receiveDone.WaitOne(0))
{
// yes - do not restart receiver!
}
// is receiver still running?
else if (CurrentState.result != null && !CurrentState.result.IsCompleted)
{
// yes - do not restart receiver!
}
else
{
// Begin receiving the data from the remote device.
CurrentState.BeginReceive(ReceiveCallback, udpClient);
}
}
The receive callback looks like this:
/// <summary>
/// End receive (with blocking) and process received data into buffer
/// </summary>
/// <param name="ar">Information about the async operation</param>
private void ReceiveCallback(IAsyncResult ar)
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject st = ar.AsyncState as StateObject;
UdpClient client = st.workSocket;
try
{
st.buffer = client.EndReceive(ar, ref receivePoint);
// Read data from the remote device.
receiveDone.Set();
}
// Since this is a callback, catch any error
// ObjectDisposedException has been seen
catch (ObjectDisposedException)
{ }
// "An existing connection was forcibly closed by remote host" has been seen
// see https://stackoverflow.com/questions/38191968/c-sharp-udp-an-existing-connection-was-forcibly-closed-by-the-remote-host for further information
catch
{
}
}
Upvotes: 0
Reputation: 941455
Your while loop calls BeginReceiveFrom() at a very high rate. Until the operating system pulls the plug and refuses to allocate more resources, shouldn't take more than a fraction of a second.
You'll have to do this differently, call BeginReceiveFrom only after you've received something. In DoReceiveFrom().
Upvotes: 1