Using C#, does broadcasting over UDP repeatedly send its packet, or just once?
I've never used this technology before and I want to temporarily broadcast small bit of info (a small one line string) over the LAN. If the receiving end isn't ready will the broadcast repeat itself or was it a one time thing? The code I'm using is from here. So what I want to start the Broadcaster one one machine and a few minutes later start the receiver and retrieve what the broadcaster sent.
Here is the code
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class Broadcst
{
public static void Main()
{
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
IPEndPoint iep1 = new IPEndPoint(IPAddress.Broadcast, 9050);
IPEndPoint iep2 = new IPEndPoint(IPAddress.Parse("192.168.1.255"), 9050);
string hostname = Dns.GetHostName();
byte[] data = Encoding.ASCII.GetBytes(hostname);
sock.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.Broadcast, 1);
sock.SendTo(data, iep1);
sock.SendTo(data, iep2);
sock.Close();
}
}
UDP by design only sends a packet once. It has no concept of handshakes (unlike TCP), error correction, or transmission guarantees. You can't even be sure that your data gets to where you send it unless you manually request checksums or something like that.
Wikipedia has a nice section on this: Reliability and congestion control solutions in UDP.
So, yes, you will need to implement transmission guarantee code if you want reliability. But what if the message from the recipient saying that the data was received is delayed? Well, then you need to implement some kind of timeout. What if the message gets lost? You need to resend the data to the recipient. How do you know if the recipient gets it this time? Etc...
If you don't want to do this, then I'd suggest looking into TCP which automatically manages this for you.
Related
I'm teaching myself some simple networking using Unity and Sockets and I'm running into problems synchronizing data between a client and server. I'm aware that there are other options using Unity Networking but, before I move on, I want to understand better how to improve my code using the System libraries.
In this example I'm simply trying to stream my mouse position over a multicast UDP socket. I'm encoding a string into a byte array and sending that array once per frame. I'm aware that sending these values as a string is un-optimal but, unless that is likely the bottleneck, I'm assuming It's ok come back to optimize that later.
Im my setup server is sending values at 60 fps, and the client is reading at the same rate. The problem I'm having is that when the client receives values it typically receives many at once. If I log the values I received with a ----- between each frame I typically get output like this:
------
------
------
------
------
------
------
119,396
91,396
45,391
18,379
-8,362
-35,342
-59,314
------
------
------
------
------
------
------
I would expect unsynchronized update cycles to lead to receiving two values per frame, but I'm not sure what might be accounting for the larger discrepancy.
Here's the Server code:
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class Server : MonoBehaviour
{
Socket _socket;
void OnEnable ()
{
var ip = IPAddress.Parse ("224.5.6.7");
var ipEndPoint = new IPEndPoint(ip, 4567);
_socket = new Socket (AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
_socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption (ip));
_socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 2);
_socket.Connect(ipEndPoint);
}
void OnDisable ()
{
if (_socket != null)
{
_socket.Close();
_socket = null;
}
}
public void Send (string message)
{
var byteArray = Encoding.ASCII.GetBytes (message);
_socket.Send (byteArray);
}
}
And the client:
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class Client : MonoBehaviour
{
Socket _socket;
byte[] _byteBuffer = new byte[16];
public delegate void MessageRecievedEvent (string message);
public MessageRecievedEvent messageWasRecieved = delegate {};
void OnEnable ()
{
var ipEndPoint = new IPEndPoint(IPAddress.Any, 4567);
var ip = IPAddress.Parse("224.5.6.7");
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
_socket.Bind (ipEndPoint);
_socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(ip,IPAddress.Any));
}
void Update ()
{
while (_socket.Available > 0)
{
for (int i = 0; i < _byteBuffer.Length; i++) _byteBuffer[i] = 0;
_socket.Receive (_byteBuffer);
messageWasRecieved (Encoding.ASCII.GetString (_byteBuffer));
}
}
}
If anybody could shed light on what I can do to improve synchronization that would be a great help.
Network I/O is subject to a large number of external influences, and TCP/IP as a protocol has few requirements. Certainly none that would provide a guarantee of the behavior you seem to want.
Unfortunately, without a good Minimal, Complete, and Verifiable code example, it's not possible to verify that your server is in fact sending data at the interval you claim. It's entirely possible you have a bug that's causing this behavior.
But if we assume that the code itself is perfect, there are still no guarantees when using UDP that datagrams won't be batched up at some point along the way, such that a large number appear in the network buffer all at once. I would expect this to happen with higher frequency when the datagrams are sent through multiple network nodes (e.g. a switch and especially over the Internet), but it could just as easily happen when the server and client are both on the same computer.
Ironically, one option that might force the datagrams to be spread out more is to pad each datagram with extra bytes. The exact number of bytes required would depend on the exact network route; to do this "perfectly" might require writing some calibration logic that tries different padding amounts until the code sees datagrams arriving at the intervals it expects.
But that would significantly increase the complexity of your network I/O code, and yet still would not guarantee the behavior you'd like. And it has some obvious negative side-effects, including the extra overhead on the network (something people using metered network connections certainly won't appreciate), as well as increasing the likelihood of a UDP datagram being dropped altogether.
It's not clear from your question whether your project actually requires multicast UDP, or if that's just something in your code because that's what some tutorial or other example you're following was using. If multicast is not actually a requirement, another thing you definitely should try is to use direct UDP without multicasting.
FWIW: I would not implement this the way you have. Instead, I would use asynchronous receive operations, so that my client receives datagrams the instant they are available, rather than only checking periodically each frame of rendering. I would also include a sequence number in the datagram, and discard (ignore) any datagrams that arrive out of sequence (i.e. where the sequence number isn't strictly greater than the most recent sequence number already received). This approach will improve (perhaps only slightly) responsiveness, but also will handle situations where the datagrams arrive out of order, or are duplicated (two of the three main delivery issues one will experience with UDP…the third being, of course, failure of delivery).
I have the following UDP server listening on Port 11000:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace UDPServer
{
class Program
{
static byte[] dataToSend = new byte[] { 1, 2, 3, 4, 5 };
// get the ip and port number where the client will be listening on
static IPEndPoint GetClientInfo()
{
// wait for client to send data
using (UdpClient listener = new UdpClient(11000))
{
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, 11000);
byte[] receive_byte_array = listener.Receive(ref groupEP);
return groupEP;
}
}
static void Main(string[] args)
{
var info = GetClientInfo(); // get client info
/* NOW THAT WE HAVE THE INFO FROM THE CLIENT WE ARE GONG TO SEND
DATA TO IT FROM SCRATCH!. NOTE THE CLIENT IS BEHIND A NAT AND
WE WILL STILL BE ABLE TO SEND PACKAGES TO IT
*/
// create a new client. this client will be created on a
// different computer when I do readl udp punch holing
UdpClient newClient = ConstructUdpClient(info);
// send data
newClient.Send(dataToSend, dataToSend.Length);
}
// Construct a socket with the info received from the client
static UdpClient ConstructUdpClient(IPEndPoint clientInfo)
{
var ip = clientInfo.Address.ToString();
var port = clientInfo.Port;
// this is the part I was missing!!!!
// the local end point must match. this should be the ip this computer is listening on
// and also the port
UdpClient client = new UdpClient(new IPEndPoint(IPAddress.Any, 11000));
// lastly we are missing to set the end points. (ip and port client is listening on)
// the connect method sets the remote endpoints
client.Connect(ip, port);
return client;
}
}
I also have opened a port in my router so when data is received from my router's gateway address, it will map to my hosting computer on 192.168.1.101:1000 as shown here:
I also have the following client defined, which is running on another machine (192.168.1.108) on the LAN:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
namespace UDPClient
{
class Program
{
static void Main(string[] args)
{
string ipOfServer = "205.172.111.250";
int portServerIsListeningOn = 11000;
// send data to server
Socket sending_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPAddress send_to_address = IPAddress.Parse(ipOfServer);
IPEndPoint sending_end_point = new IPEndPoint(send_to_address, portServerIsListeningOn);
sending_socket.SendTo(Encoding.ASCII.GetBytes("Test"), sending_end_point);
// get info
var port = sending_socket.LocalEndPoint.ToString().Split(':')[1];
// now wait for server to send data back
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, int.Parse(port));
byte[] buffer = new byte[1024];
sending_socket.Receive(buffer); // <----- we can receive data now!!!!!
}
}
}
Please notice the ipOfServer. This is my external gateway (not really since I obfuscated it, but it is not 192.168.1.101 - the internal IP of my UDP server).
When I direct the client to send to the internal LAN IP of 192.168.1.101:11000, the UDP Server connects.
However, when I use the gateway's IP address and port, the UDP Server does not connect. Since I have the port directed to 192.168.1.101:1000 in the NAT, I'm not sure what gives.
I know the NAT setting are good since I also have port 80 for HTTP and port 808 for net.tcp all working from anywhere, even outside of my network.
Please give me some insight as to what I am doing wrong.
Kind regards
It's hard to know exactly what's wrong without having access to your actual network setup. However, the scheme of creating a socket just to receive some data which is discarded, only to then create a new socket which you then "connect" to the client, seems wrong. You probably shouldn't be using Connect() with a UDP socket in the first place, and if you feel you must, you should just connect the original socket, once you have received some data.
In any case, it's really the client side of things that you need to worry about. You have already set up the router to forward datagrams inbound for the server, so the server should always be able to receive on that port. It's the return traffic to the client that is in question; the fact is, not all routers support this scenario, and always require port forwarding for UDP traffic (TCP traffic is easier because there is an on-going connection the router can maintain with the client).
I recommend that you make the server simpler – just create a single socket used to receive datagrams (and so of course don't dispose it with using). I'd also advise not using Connect() as all that will do is unnecessarily restrict the server. I.e. it will prevent the server's socket from being able to handle more than one client. If you really want to do some per-client filtering, a better mechanism is for the server to always receive all datagrams, and then check the receive-from address itself to decide how to deal with the datagram.
I am trying to write a simple UDP program in C# which sends and receives data on localhost. I am a beginner in C# but much better at MATLAB so instead of writing the server and the client in C#, I decided to send data using C# and receive it in MATLAB.
I tried two approaches to send data. Using Socket class worked, but using UdpClient class failed.
Before running this code, I run the MATLAB code to set the callback function to print the received datagram.
Only one region is active in each run. I comment out the other one.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
namespace udp1
{
class Program
{
const int port = 62745; //Chosen at random
static void Main(string[] args)
{
string str = "Hello World!";
byte[] sendBytes = Encoding.ASCII.GetBytes(str);
#region 1 Send data using socket class
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), port);
sock.SendTo(sendBuff, ipEndPoint);
Console.ReadLine();
#endregion
#region 2 Send data using UdpClient class
UdpClient sendingClient = new UdpClient(port);
sendingClient.Send(sendBytes, sendBytes.Length);
#endregion
}
}
}
I am getting
Only one usage of each socket address (protocol/network address/port)
is normally permitted
error when I run the code in region 2.
However, when I run the code in region 1 everything works as I expect and I receive the data in MATLAB without any problems.
Here is my MATLAB code. I have used this code in other applications, so I highly doubt there is anything wrong with it.
fclose(instrfindall); %Close all udp objects
%UDP Configuration
udpConfig.ipAddress = '127.0.0.1';
udpConfig.portAddress = 62745;
udpObj = udp(udpConfig.ipAddress, udpConfig.portAddress, ...
'LocalPort', udpConfig.portAddress, ...
'ByteOrder', 'bigEndian');
set(udpObj, 'datagramTerminateMode', 'on');
set(udpObj, 'datagramReceivedFcn', {#cbDataReceived, udpObj});
fopen(udpObj);
And the callback function:
function cbDataReceived(hObj, eventdata, udpObj)
bytesAvailable = get(udpObj, 'BytesAvailable');
receivedDatagram = fread(udpObj, bytesAvailable);
disp(char(receivedDatagram));
end
So, why am I getting the error in UdpClient case and not getting it in Socket case? Is there a way to avoid that error?
I understand that you are using the same port for both MATLAB and C# on the same computer. Thus, operating system does not allow to open the same port from different applications.
UDP allows sending and receiving datagrams from different ports, so use different ports for different applications if both applications are running on the same computer.
UdpClient sendingClient = new UdpClient(62746); // Some different port to listen
sendingClient.Send(sendBytes, sendBytes.Length, ipEndPoint);
preface:
I've been stumped on this for awhile now and am not having much luck finding what I need.
I have a C# (.NET 3.5) Service. One thread acts as an asynchronous listener for incoming TCP connections. When data comes in I spawn off a new worker thread to handle the data, and sends an acknowledgement back.
On a second thread in the same service we send commands out, until today it would gather information from the data base, build a new socket, connect then ship the command and I'm using the Socket.Receive to invoke blocking and wait for a response (or until a timeout occurrs).
Everything has been working great until a new client has a need to send data to us so fast (5-10 second intervals) that we can no longer open a new socket to get a command through. So I started looking into when a command needs to be sent that the "listener" thread has a client connected. If that client is connected currently use that socket instead of creating a new one.
Issue:
I'm to the point where I can send my command back on the same socket the listener receives, but when the client sends data back as the response it takes twice for the Socket.Receive method to actually fire thinking it received data. The first time it gets into my listener class, the 2nd time, in my command class where I actually want it to be.
Question:
Is there some option or something I need to do before calling my Socket.Receive method to ensure the data gets to the correct place?
In my listener class I have a list of objects "CSocketPacket"
public class CSocketPacket
{
public CSocketPacket(System.Net.Sockets.Socket socket)
{
thisSocket = socket;
this.IpAddress =
((System.Net.IPEndPoint)socket.RemoteEndPoint).Address.ToString();
}
public System.Net.Sockets.Socket thisSocket;
public byte[] dataBuffer = new byte[BUFFER_SIZE];
public string IpAddress; //Use this to search for the socket
}
Then when I send a command I'm creating a new tcp socket object:
client = new Socket(
AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ep = new IPEndPoint(
IPAddress.Parse(Strings.Trim(ipAddress)), port);
IPEndPoint LocalIp = new IPEndPoint(IPAddress.Parse(
System.Configuration.ConfigurationManager.AppSettings["SourceIP"]), port);
then I'm looking into my listener class list to see if that socket is connected:
if (listener.SocketExists(ipAddress))
{
// set the client socket in this class to the
// instance of the socket from the listener class
SocketIndex = listener.FindSocketInList(ipAddress);
if (SocketIndex != -1)
{
// might need to figure out how to avoid copying the socket
// to a new variable ???
client = listener.ConnectedSockets[SocketIndex].thisSocket;
SocketBeingReUsed = true;
}
}
else
{
// try to connect to the client
client.Connect(ep);
}
finally I go through my steps of sending and receiving
if (client.Connected)
{
if (client.Poll(1000, SelectMode.SelectWrite))
{
int sentAmount = Send(ref client);
client.ReceiveTimeout = 90000; //90 seconds
returnData = ReceiveData(ref client, sentAmount);
}
}
everything works up to the point in my ReceiveData(ref client, sentAmount) method where I call the Socket.Receive(data, total, Socket.ReceiveBufferSize, SocketFlags.None); method.
I've been using a tool called Hercules to test sending/receiving packets across two machines on my home network.
Does anyone have any ideas of what I can do to solve this? I do apologize for such a lengthy question but I want to try to give as much info and not paste my entire project. I'm up for any suggestions.
Disclaimer: I wrote this code approx 3 years ago, so I'm pry doing things I shouldn't be I'm sure :P
Thanks to all who read this.
Sincerely,
Chris
OK, so now I'm following along! Given what you've said in the comments above, then the way to solve the problem is to have a single class/thread that reads from the socket (which is the correct way to read from sockets anyway) and then it will coordinate which class gets the data. I think it might work a little like the Command Design Pattern.
I read 2 C# chat source code & I see a problem:
One source uses Socket class:
private void StartToListen(object sender , DoWorkEventArgs e)
{
this.listenerSocket = new Socket(AddressFamily.InterNetwork , SocketType.Stream , ProtocolType.Tcp);
this.listenerSocket.Bind(new IPEndPoint(this.serverIP , this.serverPort));
this.listenerSocket.Listen(200);
while ( true )
this.CreateNewClientManager(this.listenerSocket.Accept());
}
And other one uses TcpListener class:
server = new TcpListener(portNumber);
logger.Info("Server starts");
while (true)
{
server.Start();
if (server.Pending())
{
TcpClient connection = server.AcceptTcpClient();
logger.Info("Connection made");
BackForth BF = new BackForth(connection);
}
}
Please help me to choose the one. I should use Socket class or TcpListener class. Socket connection is TCP or UDP? Thanks.
UDP is connectionless, but can have a fake connection enforced at both ends on the socket objects. TCP is a stream protocol (what you send will be received in chunks on the other end), and additionally creates endpoint sockets for each accepted socket connection (the main listening socket is left untouched, although you'd probably need to call listen() again). UDP uses datagrams, chunks of data which are received whole on the other side (unless the size is bigger than the MTU, but that's a different story).
It looks to me like these two pieces of code are both using TCP, and so as the underlying protocol is the same, they should be completely compatible with each other. It looks as if you should use the second bit of code since it's higher level, but only the server can really use this, the client needs a different bit of code since it doesn't listen, it connects... If you can find the 'connecting' code at the same level of abstraction, use that.