Where is data sent by UDP stored? - c#

I had never used UDP before, so I gave it a go. To see what would happen, I had the 'server' send data every half a second, and the client receive data every 3 seconds. So even though the server is sending data much faster than the client can receive, the client still receives it all neatly one by one.
Can anyone explain why/how this happens? Where is the data buffered exactly?
Send
class CSimpleSend
{
CSomeObjServer obj = new CSomeObjServer();
public CSimpleSend()
{
obj.changedVar = varUpdated;
obj.threadedChangeSomeVar();
}
private void varUpdated(int var)
{
string send = var.ToString();
byte[] packetData = System.Text.UTF8Encoding.UTF8.GetBytes(send);
string ip = "127.0.0.1";
int port = 11000;
IPEndPoint ep = new IPEndPoint(IPAddress.Parse(ip), port);
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
client.SendTo(packetData, ep);
Console.WriteLine("Sent Message: " + send);
Thread.Sleep(100);
}
}
All CSomeObjServer does is increment an integer by one every half second
Receive
class CSimpleReceive
{
CSomeObjClient obj = new CSomeObjClient();
public Action<string> showMessage;
Int32 port = 11000;
UdpClient udpClient;
public CSimpleReceive()
{
udpClient = new UdpClient(port);
showMessage = Console.WriteLine;
Thread t = new Thread(() => ReceiveMessage());
t.Start();
}
private void ReceiveMessage()
{
while (true)
{
//Thread.Sleep(1000);
IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, port);
byte[] content = udpClient.Receive(ref remoteIPEndPoint);
if (content.Length > 0)
{
string message = Encoding.UTF8.GetString(content);
if (showMessage != null)
showMessage("Recv:" + message);
int var_out = -1;
bool succ = Int32.TryParse(message, out var_out);
if (succ)
{
obj.alterSomeVar(var_out);
Console.WriteLine("Altered var to :" + var_out);
}
}
Thread.Sleep(3000);
}
}
}
CSomeObjClient stores the variable and has one function (alterSomeVar) to update it
Ouput:
Sent Message: 1
Recv:1
Altered var to :1
Sent Message: 2
Sent Message: 3
Sent Message: 4
Sent Message: 5
Recv:2
Altered var to :2
Sent Message: 6
Sent Message: 7
Sent Message: 8
Sent Message: 9
Sent Message: 10
Recv:3
Altered var to :3

The operating system kernel maintains separate send and receive buffers for each UDP and TCP socket. If you google SO_SNDBUF and SO_RCVBUF you'll find lots of information about them.
When you send data, it is copied from your application space into the send buffer. From there it is copied to the network interface card, and then onto the wire. The receive side is the reverse: NIC to receive buffer, where it waits until you read it. Additionally copies and buffering can also occur, depending on the OS.
It is critical to note that the sizes of these buffers can vary radically. Some systems might default to as little as 4 kilobytes, while others give you 2 megabytes. You can find the current size using getsockopt() with SO_SNDBUF or SO_RCVBUF and likewise set it using setsockopt(). But many systems limit the size of the buffer, sometimes to arbitrarily small amounts. This is typically a kernel value like net.core.wmem_max or net.core.rmem_max, but the exact reference will vary by system.
Also note that setsockopt() can fail even if you request an amount less than the supposed limit. So to actually get a desired size, you need to repeatedly call setsockopt() using decreasing amounts until it finally succeeds.
The following page is a Tech Note from my company which touches on this topic a little bit and provides references for some common systems: http://www.dataexpedition.com/support/notes/tn0024.html

It looks to me like the UdpClient-Class provides a buffer for received data. Try using a socket directly. You might also want to set that sockets ReceiveBufferSize to zero, even though I believe it is only used for TCP connections.

Related

C# Socket.Receive() malfunctions when TCP package is larger than MTU

I'm using C# Socket class to send/receive TCP messages to/from our server by short connection. The pseudo-code (exclude some false tolerant logic to make it clear) is as followings.
class MyTCPClient {
private Socket mSocket;
MyTCPClient() {
mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
void Connect(ipEndpoint, sendTimeOut, receiveTimeOut) {
mSocket.Connect(ipEndpoint);
mSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, sendTimeOut);
mSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, receiveTimeOut);
}
void Send(msg) {
mSocket.Send(msg);
}
void Receive(data) {
ByteStreamWriter bsw = new ByteStreamWriter();
int totalLen = 0;
while (true) {
byte[] temp = new byte[1024];
int len = mSocket.Receive(temp, SocketFlags.None);
System.Threading.Thread.Sleep(50); // This is the weirdest part
if (len <= 0) break;
totalLen += len;
bsw.WriteBytes(temp);
}
byte[] buff = bsw.GetBuffer();
data = new byte[totalLen];
Array.Copy(buff, 0, data, 0, totalLen);
}
~MyTCPClient() {
mSocket.Close();
}
}
I was using this class to request the same message from our server several times by short connection, and the following things occurred (only when the message size was larger than one MTU -- 1500 bytes).
If the "Sleep(50)" was commented out, the most of the times (90%) I received wrong "data", specifically to say, the "totalLen" was right, but the "data" was wrong.
If I replaced "Sleep(50)" to "Sleep(10)", about half of the times I received wrong "data", and "totalLen" was also right always.
If I used "Sleep(50)", occasionally, I received wrong "data".
I can guarantee that, every time, our server sent the right data, and the client received the right data too at TCP layer (I used WireShark to monitor all messages through the port I used). Is there anyone who can help to answer why my C# code cannot get the right data?
Also, if I use mSocket.Available instead of the return value of Socket.Receive() to judge the while loop, I would always get the right data and data length...
You don't truncate temp to len bytes before writing it. All the bytes after len in temp have not been filled with current data and thus contain nonsensical, stale date.
When copying to another stream you could use stream.Write(temp, 0, len)

Udp reads empty bytes after first time - mono android

On my Xamarin.Android app I'm sending udp broadcast message to find my servers on the local LAN.
My servers then return the MachineName they run on which I display in a ListView on my app in the form of
<MachineName> - <Ip address>
This all works well on the first time, however from the second time on all it reads is empty bytes.
The number of bytes it reads is correct but they are all zero.
Here is the code:
private static void ListenForBroadcastResponses()
{
udp.BeginReceive(OnBroadcastResponse, new object());
}
private static void OnBroadcastResponse(IAsyncResult ar)
{
// Recieve the message
IPEndPoint ip = new IPEndPoint(IPAddress.Any, port);
byte[] bytes = udp.EndReceive(ar, ref ip);
// Decode it
string message = Encoding.ASCII.GetString(bytes);
// If message is the awaited message from client or from the awaited port
if (ip.Port == port) //|| message == BRDCAST_ANSWER)
{
// Raise server found event
var handler = ServerFound;
if (handler != null)
handler(null, new ServerEventArgs
{
Server = new Server(message, ip.Address)
});
}
// Start listening again
ListenForBroadcastResponses();
}
Debug screenshots:
First time full bytes are recieved:
Second time and on bytes are empty:
What is wrong here?
Eventually I figured it out. It seems to be a bug caused by multiple threads trying to listen simultaneously (see this post) to replies so I'll post my solution:
I've added a RecieveTimeout of X seconds to the UdpClient.
Upon timeout, I execute an EndRecieve and Close method calls.
This will trigger the callback passed in BeginRecieve to execute so I've added a check to the callback method if the client is still open
if (udp.Client != null) ...
It fixed things for me, so hopefully it will help others

Object oriented comunication via TCP in C#

I'm developing a simple application that will receive data from a hardware via TCP.
I've searched a bit on the Internet how to develop a program to receive TCP data, but have not found anything that I'm happy with. It is either a very simplified descriptions of how to work with TCP in C # or it is description of advanced frameworks.
I want a simple best practice of how to organize the communication part of my program in a good object-oriented manner. Any suggestions?
Ideally, I want the different structures that are sent via TCP are stored in the corresponding struct in the program
structure of what is sent:
Head
{
Int16 Mode;
Time Start_time //(Unix time)
Int16 Number of records
}
for each record if mode == 1
char[20] Name_of_record
for each record
float Value_of_record //(hardware-specific float)
Int16 Flag_of_record
Foot
{
Time Stop_time //(Unix time)
}
And this is sent once a minute.
There is no overhead. It just sends out the value of all variables and no more
Edit
I do not have any control over the server.
We can receive TCP messages using asynchronous communication.
Initialize Server Socket and try to connect:
// Specify the size according to your need.
private byte[] bytData = new byte[1024 * 50000];
private Socket oServerSocket;
private void WindowLoaded(object sender, RoutedEventArgs e)
{
try
{
// We are using TCP sockets
this.oServerSocket = new Socket(
addressFamily: AddressFamily.InterNetwork,
socketType: SocketType.Stream,
protocolType: ProtocolType.Tcp);
// Assign the any IP of the hardware and listen on port number which the hardware is sending(here it's 5656)
var oIPEndPoint = new IPEndPoint(address: IPAddress.Any, port: 5656);
// Bind and listen on the given address
this.oServerSocket.Bind(localEP: oIPEndPoint);
this.oServerSocket.Listen(backlog: 4);
// Accept the incoming clients
this.oServerSocket.BeginAccept(this.OnAccept, null);
this.oLogger.WriteLog("Server started");
}
catch (Exception ex)
{
// Handle Exception
}
}
On Successful connection:
private void OnAccept(IAsyncResult ar)
{
try
{
var oClientSocket = this.oServerSocket.EndAccept(asyncResult: ar);
// Start listening for more clients
this.oServerSocket.BeginAccept(callback: this.OnAccept, state: null);
// Once the client connects then start receiving the commands from her
oClientSocket.BeginReceive(
buffer: this.bytData,
offset: 0,
size: this.bytData.Length,
socketFlags: SocketFlags.None,
callback: this.OnReceive,
state: oClientSocket);
}
catch (Exception ex)
{
// Handle Exception
}
}
Process the message received:
private void OnReceive(IAsyncResult ar)
{
try
{
var oClientSocket = (Socket)ar.AsyncState;
oClientSocket.EndReceive(asyncResult: ar);
/* Process the data here
BitConverter.ToInt32(value: this.bytData, startIndex: 0);
string SomeString= Encoding.ASCII.GetString(bytes: this.bytData, index: 8, count: 5);
*/
// Specify the size according to your need.
this.bytData = null;
this.bytData = new byte[1024 * 50000];
oClientSocket.BeginReceive(
buffer: this.bytData,
offset: 0,
size: this.bytData.Length,
socketFlags: SocketFlags.None,
callback: this.OnReceive,
state: oClientSocket);
}
catch (Exception ex)
{
// Handle Exception
}
}
Usually the steps are the same:
1) Read the data from the tcp stream and store it in a buffer (usually byte arrays).
2) Continuously check the buffer (every time you update it) to determine whether a complete packet is arrived.
3) Parse the buffer and extract the packet to the desired OO object
4) Add the object to a queue to further processing or invoke a background thread to consume the packet object.
To send data through the output stream is pretty much the same in the inverse order.
Things can get complicated/noisy/a pain when dealing with the buffer. You'll need to deal with the binary data to determine when a packet ends and another begins. Of course this is relative to the protocol of the device you're communicating, if it send fixed length packets or start/stop byte(s) etc...
At this point there is no standard solution since the code you'll write depends on the data sent by the device.
EDIT: You updated your question with a sample code, however is not the structure of the record that matter, that part is simple and verbose to write (if your struct has a int field you read 4 bytes from the buffer and write on that field using BitConverter class to convert bytes to int for example). You'll need to read the hardware manual to check the format it sends the data (again, start/stop bytes, fixed length etc..).
This is very abstract because it's specific to each case, there is no "baked solution". Also, seems like you do not understand how streams/tcp connections/binary packets works, what makes you think that this is a problem of tcp connections, but is not. Tcp connections is just byte streams sent over a network, you can use the same pattern to read binary data from files on your disk or from a serial port.

Sending a string to a server from a client in C#

I am writing a simple test program to send a string from a client to a server and then display the text on the server program. How would I go about doing this.
Here is my client code.
using System;
using System.Net;
using System.Net.Sockets;
class client
{
static String hostName = Dns.GetHostName();
public static void Main(String[] args)
{
String test = Console.ReadLine();
IPHostEntry ipEntry = Dns.GetHostByName(hostName);
IPAddress[] addr = ipEntry.AddressList;
//The first one in the array is the ip address of the hostname
IPAddress ipAddress = addr[0];
TcpClient client = new TcpClient();
//First parameter is Hostname or IP, second parameter is port on which server is listening
client.Connect(ipAddress, 8);
client.Close();
}
}
Here is my server code
using System;
using System.Net;
using System.Net.Sockets;
class server
{
static int port = 8;
static String hostName = Dns.GetHostName();
static IPAddress ipAddress;
public static void Main(String[] args)
{
IPHostEntry ipEntry = Dns.GetHostByName(hostName);
//Get a list of possible ip addresses
IPAddress[] addr = ipEntry.AddressList;
//The first one in the array is the ip address of the hostname
ipAddress = addr[0];
TcpListener server = new TcpListener(ipAddress,port);
Console.Write("Listening for Connections on " + hostName + "...\n");
//start listening for connections
server.Start();
//Accept the connection from the client, you are now connected
Socket connection = server.AcceptSocket();
Console.Write("You are now connected to the server\n\n");
int pauseTime = 10000;
System.Threading.Thread.Sleep(pauseTime);
connection.Close();
}
}
You can use the Send and Receive overloads on Socket. Asynchronous version exists as well, through the BeginSomething & EndSomething methods.
You send raw bytes, so you'll need to decide upon a protocol however simple. To send some text, select an encoding (I would use UTF-8) and get the raw bytes with Encoding.GetBytes.
Example:
Byte[] bytes = Encoding.UTF8.GetBytes("Royale With Cheese");
UTF8 is a static property on the Encoding class, it's there for your convenience.
You can then send the data to the server/client with:
int sent = connection.Send(bytes);
Receive:
Byte[] bytes = new Bytes[100];
int received = connection.Receive(bytes);
This looks easy, but there are caveats. The connection may at any time be dropped, so you must be prepared for exceptions, especially SocketException. Also if you look at the examples you can see that I have two variables sent and received. They hold how many bytes Send and Receive actually sent. You cannot rely on the socket sending or receiving all the data (especially not when receiving, what if the other party sent less than you expected?)
One way to do this is too loop and send until all the data is indicated as sent:
var bytes = Encoding.UTF8.GetBytes("Royale With Cheese");
int count = 0;
while (count < bytes.Length) // if you are brave you can do it all in the condition.
{
count += connection.Send(
bytes,
count,
bytes.Length - count, // This can be anything as long as it doesn't overflow the buffer, bytes.
SocketFlags.None)
}
Send and Receive are synchronous, they block until they've sent something. You should probably set some kind of timeout value on the socket (Socket.SendTimeout & Socket.ReceiveTimeout.) The default is 0 which means they may block forever.
Now how about receiving? Let's try to do a similar loop.
int count = 0;
var bytes = new Byte[100];
do
{
count += connection.Receive(
bytes,
count,
bytes.Length - count,
SocketFlags.None);
} while (count < bytes.Length);
Hmm. Well... what happens if the client sends less than a 100? We would block until it hits the timeout, if there is one, or the client sends enough data. What happens if the client sends more than a 100? You will only get the 100 first bytes.
In your case we could try reading very small amounts and print. Read, print, loop:
var sunIsBurning = true;
while (sunIsBurning) {
var bytes = new Byte[16];
int received = socket.Receive(bytes);
if (received > 0)
Console.Out.WriteLine("Got {0} bytes. START:{1}END;", received, Encoding.UTF8.GetString(bytes));
}
Here we say "receive data in 16 byte chunks as long as sunIsBurning, decode as UTF-8". This means the data sent by the other party must be UTF-8 or you'll get an exception (it should probably be caught by you) This also means that the server will only stop receiving when the connection fails.
If you have received 15 bytes, and the client kills the connection, those 15 bytes will never be printed. You will need better error handling for that :)
An uncaught exception will kill your application in most cases; not desirable for a server.
"connection fails" could mean a lot of things, it might be that the connection was reset by the peer or your network card caught fire.

C# Socket BeginReceive / EndReceive capturing multiple messages

Problem:
When I do something like this:
for (int i = 0; i < 100; i++)
{
SendMessage( sometSocket, i.ToString());
Thread.Sleep(250); // works with this, doesn't work without
}
With or without the sleep the server logs sending of separate messages. However without the sleep the client ends up receiving multiple messages in single OnDataReceived so the client will receive messages like:
0,
1,
2,
34,
5,
678,
9 ....
Server sending Code:
private void SendMessage(Socket socket, string message)
{
logger.Info("SendMessage: Preparing to send message:" + message);
byte[] byteData = Encoding.ASCII.GetBytes(message);
if (socket == null) return;
if (!socket.Connected) return;
logger.Info("SendMessage: Sending message to non " +
"null and connected socket with ip:" + socket.RemoteEndPoint);
// Record this message so unit testing can very this works.
socket.Send(byteData);
}
Client receiving code:
private void OnDataReceived(IAsyncResult asyn)
{
logger.Info("OnDataReceived: Data received.");
try
{
SocketPacket theSockId = (SocketPacket)asyn.AsyncState;
int iRx = theSockId.Socket.EndReceive(asyn);
char[] chars = new char[iRx + 1];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
int charLen = d.GetChars(theSockId.DataBuffer, 0, iRx, chars, 0);
System.String szData = new System.String(chars);
logger.Info("OnDataReceived: Received message:" + szData);
InvokeMessageReceived(new SocketMessageEventArgs(szData));
WaitForData(); // .....
Socket Packet:
public class SocketPacket
{
private Socket _socket;
private readonly int _clientNumber;
private byte[] _dataBuffer = new byte[1024]; ....
My hunch is it's something to do with the buffer size or its just the between the OnDataReceived and EndReceive we're getting multiple messages.
Update: It turns out when I put a Thread.Sleep at the start of OnDataReceived it gets every message. Is the only solution to this wrapping my message in a prefix of length and an string to signify the end?
This is expected behaviour. A TCP socket represents a linear stream of bytes, not a sequence of well-delimited “packets”. You must not assume that the data you receive is chunked the same way it was when it was sent.
Notice that this has two consequences:
Two messages may get merged into a single callback call. (You noticed this one.)
A single message may get split up (at any point) into two separate callback calls.
Your code must be written to handle both of these cases, otherwise it has a bug.
There is no need to abandon Tcp because it is stream oriented.
You can fix the problems that you are having by implementing message framing.
See
http://blogs.msdn.com/malarch/archive/2006/06/26/647993.aspx
also:
http://nitoprograms.blogspot.com/2009/04/message-framing.html
TCP sockets don't always send data right away -- in order to minimize network traffic, TCP/IP implementations will often buffer the data for a bit and send it when it sees there's a lull (or when the buffer's full).
If you want to ensure that the messages are processed one by one, you'll need to either set socket.NoDelay = true (which might not help much, since data received may still be bunched up together in the receive buffer), implement some protocol to separate messages in the stream (like prefixing each message with its length, or perhaps using CR/LF to separate them), or use a message-oriented protocol like SCTP (which might not be supported without additional software) or UDP (if you can deal with losing messages).

Categories

Resources