receive all udp packets on multicast - c#

i am using the c# UdpClient (client in code) to receive data on a multicast group.
In a while loop the follwing happens:
while(receiving)
//First i check if data is available, polltime = 100ms
if(client.Client.Poll(polltime, SelectMode.SelectRead))
{
//if data is present
data = client.Receive(ref remoteEp);
...
}
else
{
//100ms
Thread.sleep(sleeptime);
}
somehow i often miss packets (if there are more than one) that should be on the multicast and udp packet loss can´t be that much i guess.
Can the receiving be done better or does anyone know the problem)
Edit1:
The data that is sent are also by c# UdpClient and are byte arrays with the siz of 1024
Edit2:
In Wireshark i could see that the missing packets are not arriving, so the problem may be really udp packet loss?

I'd suggest the following implementation of the receive loop:
while (receiving)
{
try
{
// block until data is present
data = client.Receive(ref remoteEp);
...
}
catch (SocketException ex)
{
receiving = false;
}
}

Related

Why isn't TcpListener listening?

We have a C++ v100 application that is processing every event in our system, listening on port 1705, running off the Hostname. (it works perfectly for the C++ app, and we don't want to change anything in the c++ code) We are trying to intercept some of those events into a C# 4.5.2 solution, simply to display specific events in our new web system.
I have coded the following, in an attempt to listen to port 1705 traffic... but I never receive any data. (I can create events that get sent to 1705)
The following code runs, and it makes it to 'Waiting for a connection', but never makes it to 'Connected!'. If you see any reason in the following code as to why I wouldn't be receiving data, please let me know:
private void PortListener()
{
TcpListener server = null;
try
{
// Set the TcpListener on port 13000.
var port = 1705;
var localAddr = IPAddress.Parse(Dns.GetHostAddresses(Environment.MachineName)[0].ToString());
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Buffer for reading data
var bytes = new byte[256];
// Enter the listening loop.
while (true)
{
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
var client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
// Get a stream object for reading and writing
var stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
var data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
// Process the data sent by the client.
data = data.ToUpper();
//TODO: Process the data
}
// Shutdown and end connection
client.Close();
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server?.Stop();
}
}
Make sure that you are binding/listening to the right ip-address. If you bind/listen on localhost (127.0.0.1) you can only connect from the same host.
Check what
Dns.GetHostAddresses(Environment.MachineName)[0].ToString());
really produces.
I'm doing this all wrong. In order to listen to an already opened Port, I need to use a TcpClient to connect and listen. Only a single TcpListener is allowed per port. Several TcpClients can connect at once. Sigh.

Reading entire response through socket with good performance

I have written some code to get a webpage through a proxy using sockets. In essence, it works but reading the response has some strange behavior that is really tripping me up.
When I go to read the response after sending the GET command it is 0 bytes. It takes a few ticks before there is data to read. I don't want to hard code a delay in here as I am trying to write performant reliable code so I have coded a while loop that keeps reading the response until it more than 0.
This works for the first chunk but trying to read subsequent chunks is a problem. If i instantly try to read the response it will be 0 bytes so I need to check the subsequent reads also if they are greater than 0.
So to read the whole response I tried to check if the response is equal to the size of the buffer. If it is equal to the size of the buffer then I carry on and try to read another chunk. This has a few issues also. Sometimes the response will read less than the size of the buffer but there is still more to come, i guess I am reading it faster than they are sending it because if I add a Thread.Sleep() then the buffer will always be full but I don't think it is good practice to hardcode this because I don't know how fast they will be sending. This code will be used for multiple things and will be running on hundreds of threads so performance is everything.
Also if the last chunk just happens to be the size of my buffer then I think the loop will lock, This whole approach I have taken is horrible but I can't see how I should be reading it. I have seen the asynchronous examples but I think that will add to the overall complexity of my code as I just have 1 set process which I will run in many threads.
How do I efficiently read the response when I can't guarantee the next chunk will have data or be full even if there is more data to come?
Sorry for long text but I wanted to explain my thinking. Here is my code:
// Data buffer for incoming data.
byte[] bytes = new byte[1024];
// Connect to a remote device.
try
{
var proxyIpAddress = IPAddress.Parse("123.123.123.123"); //omitted
IPEndPoint remoteEP = new IPEndPoint(proxyIpAddress, 60099);
// Create a TCP/IP socket.
Socket sender = new Socket(proxyIpAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.
try
{
sender.Connect(remoteEP);
Console.WriteLine("Socket connected to {0}",
sender.RemoteEndPoint.ToString());
sender.Send(Encoding.ASCII.GetBytes($"CONNECT google.com:80 HTTP/1.0\r\n\r\n"));
int bytesRec = 0;
while (bytesRec == 0)
{
// Receive the response from the remote device.
bytesRec = sender.Receive(bytes);
Console.WriteLine("{0}",
Encoding.ASCII.GetString(bytes, 0, bytesRec));
}
//clear buffer
bytes = new byte[1024];
bytesRec = 0;
sender.Send(Encoding.ASCII.GetBytes("GET / HTTP/1.0\r\n\r\n"));
//wait for response
while (bytesRec == 0) //if i dont add this it returns before it actually gets data
{
// Receive the response from the remote device.
bytesRec = sender.Receive(bytes);
Console.WriteLine("{0}",
Encoding.ASCII.GetString(bytes, 0, bytesRec));
}
if(bytes.Length == bytesRec) //full buffer so likely more but maybe not if final packet exactly 1024?
{
while (bytes.Length == bytesRec) //again if i miss this it returns too early
{
int subsequentBytes = 0;
while(subsequentBytes == 0) //this can get stuck if last packet exactly size of buffer i think
{
subsequentBytes = sender.Receive(bytes);
Console.WriteLine("{0}",
Encoding.ASCII.GetString(bytes, 0, subsequentBytes));
//this doesn't work. even when there are subsequent bytes sometimes it reads less
//than the size of the buffer so it exits prematurely. If I add a Thread.Sleep() here
// then it works but I don't want to hardcode the delay. How do I read this buffer properly?
Thread.Sleep(1000);
if (subsequentBytes > 0) bytesRec = subsequentBytes;
}
}
}
// Release the socket.
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
I understand this is difficult to follow and a lot of writing so if anyone perseveres with this they have my gratitude as the only option I can see is hardcoded pauses which will hurt performance and may still have issues.
EDIT
I have done some experiementing with different servers. If I ping the server then set a Thread.Sleep(pingValue) it works fine but if i set the sleep to lower than ping i get same issue.
Is there some good way with the .net libraries to account for this latency so I am not under/overestimating?

Listen To Specific Port With UDPClient & Get Transmitted Packets

First of all, I apologize for the wrong usage of terminology.
I have a sensor on my local network. It broadcasts current temperature values to everyone on the network on port 35333. I want to create a C# console program that continuously receives packets from this sensor.
This is my current code:
public static UdpClient Client = new UdpClient(35333);
private static async void Start()
{
Client.BeginReceive(new AsyncCallback(recv), null);
}
private static void recv(IAsyncResult res)
{
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
byte[] received = Client.EndReceive(res, ref RemoteIpEndPoint);
//Process codes
Client.BeginReceive(new AsyncCallback(recv), null);
}
The code above works, however here's the problem: I keep received same byte array all the time.
...
[114][51][57][48][48][77][72][112]
[114][51][57][48][48][77][72][112]
[114][51][57][48][48][77][72][112]
[114][51][57][48][48][77][72][112]
[114][51][57][48][48][77][72][112]
...
As far as I know, and again, excuse my poor networking knowledge, I must somehow send an acknowledgement back to this sensor, so it starts sending me the ''real'' data.
Any tips or suggestions welcomed!
There are at least two possibilities here.
First, this may just be the temperature, and it isn't changing. In that case, you need to parse the bytes in the way that the sensor's spec dictates.
Second, if this is indeed the packet that needs an acknowledgement, then you will need to find out which port the sensor listens on (from the spec), and what the acknowledgement packet should look like (from the spec) and send it to that port.
The key here is reviewing the documents that came with the sensor.
New code would sit inside recv method and appear similar to the following:
private static void recv(IAsyncResult res)
{
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
byte[] received = Client.EndReceive(res, ref RemoteIpEndPoint);
//Pseudo code
//start_packet is the packet of bytes above from the sensor
If (received == start_packet)
{
//send acknowledgement
}
//Process codes
Client.BeginReceive(new AsyncCallback(recv), null);
}

TcpClient missing data

I am trying to write network part for my game in C# using System.Net.Sockets and TcpClient class.
Each update server is sending information to client.
All information is built into 2kb packets, so in 1 update 1-2-3-5-10 packets can be sent.
Client is checking information and if information has right format - then reading it.
Everything is working fine, until server starts trying to send too many packets.
When it happens client time to time is receiving packets with wrong data 1 of 20-50 packets usually.
For example, 1-2 packets for 1 update usually are received fine, 3-10 packets for update giving wrong data streams.
If I am starting several clients in 1 time, that should get same data streams from server - they get different numbers of success and fail data streams.
What am I doing wrong, and how can I evade this wrong data streams?
Am I just sending too much data in 1 ms and it is needed to send it over time?
This is the sending information:
TcpClient client;
public void SendData(byte[] b)
{
//Try to send the data. If an exception is thrown, disconnect the client
try
{
lock (client.GetStream())
{
client.GetStream().BeginWrite(b, 0, b.Length, null, null);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
This is the receiving information:
byte[] readBuffer;
int byfferSize = 2048;
private void StartListening()
{
client.GetStream().BeginRead(readBuffer, 0, bufferSize, StreamReceived, null);
}
private void StreamReceived(IAsyncResult ar)
{
int bytesRead = 0;
try
{
lock (client.GetStream())
{
bytesRead = client.GetStream().EndRead(ar); // просмотр длины сообщения
}
}
catch (Exception ex)
{ MessageBox.Show(ex.Message); }
//An error happened that created bad data
if (bytesRead == 0)
{
Disconnect();
return;
}
//Create the byte array with the number of bytes read
byte[] data = new byte[bytesRead];
//Populate the array
for (int i = 0; i < bytesRead; i++)
data[i] = readBuffer[i];
//Listen for new data
StartListening();
//Call all delegates
if (DataReceived != null)
DataReceived(this, data);
}
It is main network code.
I don't know what you do with the data after you've received it, but it's quite possible that you're not reading all of the data from the connection. You have:
bytesRead = client.GetStream().EndRead(ar);
There's no guarantee that the number of bytes you've read are all of the bytes that the server sent. For example, the server could have sent 2,048 bytes, but when you called Read, there were only 1,024 bytes available. The rest of them are still "in transit." As the documentation for NetworkStream.Read says:
The Read operation reads as much data as is available, up to the number of bytes specified by the size parameter
You could be getting partial packets. If your DataReceived handlers assume that the data buffer contains a complete packet, then you're going to have problems.
To reliably read from a network stream, you need to know how much data you're supposed to read, or you need a record separator. Something has to make sure that if you're expecting a complete packet that you get a complete packet before you try to process it. Your code just checks to see if bytesRead is not 0. If it's anything else, you just pass it on. This is going to be a problem unless your DataReceived handlers know how to buffer partial packets.
On another note, you really don't need to lock the network stream. Unless you can have several threads reading from the same stream. And that would be disastrous. Ditch the lock. You don't need it.

How to Debug Network Errors (Specifically ICMP)

I have a server/client type app, Wireshark shows that the client has sent a packet to the server, the server had given the expected response but shows a ICMP Destination port unreachable error.
I'm using a function that was on the MDSN website which has worked for me before.
EDIT: To update I have checked that the packet is being sent after the phone has started listening, I have tried other ports. There is no socket exception so i'm just looking for the best way to go about debugging network errors.
Any ideas?
public string Receive()
{
string response = "Operation Timeout";
// We are receiving over an established socket connection
if (udpSocket != null)
{
// Create SocketAsyncEventArgs context object
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = new DnsEndPoint(SERVER, RECIVEPORT);
// Setup the buffer to receive the data
socketEventArg.SetBuffer(new Byte[MAX_BUFFER_SIZE], 0, MAX_BUFFER_SIZE);
// Inline event handler for the Completed event.
// Note: This even handler was implemented inline in order to make this method self-contained.
socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
// Retrieve the data from the buffer
response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
response = response.Trim('\0');
}
else
{
response = e.SocketError.ToString();
}
_clientDone.Set();
});
// Sets the state of the event to nonsignaled, causing threads to block
_clientDone.Reset();
// Make an asynchronous Receive request over the socket
Debug.WriteLine("Listening now:" + DateTime.Now.Second + ":" + DateTime.Now.Millisecond);
try
{
Debug.WriteLine("No socket exception");
udpSocket.ReceiveFromAsync(socketEventArg);
}
catch (SocketException e)
{
Debug.WriteLine(e.SocketErrorCode);
}
// Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
// If no response comes back within this time then proceed
_clientDone.WaitOne(TIMEOUT_MILLISECONDS);
}
else
{
response = "Socket is not initialized";
}
return response;
}
"ICMP Destination port unreachable" means that there was no application bound to the port you were sending to. Make sure that your sendto() is targeting to correct IP address and port number. Also check that your listener is calling bind() on INADDR_ANY and the correct port. A common mistake is to forget to convert the port number to network byte order (big-endian). See htons().

Categories