Skip to content

Instantly share code, notes, and snippets.

@darkguy2008
Last active December 7, 2022 23:51
Embed
What would you like to do?
Simple C# UDP server/client in 56 lines
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace UDP
{
public class UDPSocket
{
private Socket _socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
private const int bufSize = 8 * 1024;
private State state = new State();
private EndPoint epFrom = new IPEndPoint(IPAddress.Any, 0);
private AsyncCallback recv = null;
public class State
{
public byte[] buffer = new byte[bufSize];
}
public void Server(string address, int port)
{
_socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.ReuseAddress, true);
_socket.Bind(new IPEndPoint(IPAddress.Parse(address), port));
Receive();
}
public void Client(string address, int port)
{
_socket.Connect(IPAddress.Parse(address), port);
Receive();
}
public void Send(string text)
{
byte[] data = Encoding.ASCII.GetBytes(text);
_socket.BeginSend(data, 0, data.Length, SocketFlags.None, (ar) =>
{
State so = (State)ar.AsyncState;
int bytes = _socket.EndSend(ar);
Console.WriteLine("SEND: {0}, {1}", bytes, text);
}, state);
}
private void Receive()
{
_socket.BeginReceiveFrom(state.buffer, 0, bufSize, SocketFlags.None, ref epFrom, recv = (ar) =>
{
State so = (State)ar.AsyncState;
int bytes = _socket.EndReceiveFrom(ar, ref epFrom);
_socket.BeginReceiveFrom(so.buffer, 0, bufSize, SocketFlags.None, ref epFrom, recv, so);
Console.WriteLine("RECV: {0}: {1}, {2}", epFrom.ToString(), bytes, Encoding.ASCII.GetString(so.buffer, 0, bytes));
}, state);
}
}
}
using System;
namespace UDP
{
class Program
{
static void Main(string[] args)
{
UDPSocket s = new UDPSocket();
s.Server("127.0.0.1", 27000);
UDPSocket c = new UDPSocket();
c.Client("127.0.0.1", 27000);
c.Send("TEST!");
Console.ReadKey();
}
}
}
@FoolishFrost
Copy link

I don't mean to dismiss your work, but you might want to be advised that your code above does not deal with constant streams of data.

If data is being sent in bursts, then you get back corrupted data on the receiving system. It will respond with data from send 8 out of 10 in a burst, twice, and be missing item 9 of the burst of sends. (or other combinations)

@Blacklock
Copy link

@FoolishFrost How would you suggest the code be improved?

@FoolishFrost
Copy link

At this point, I have to say it was due to the ordering of the _socket.BeginReceiveFrom on line 51. Due to the ordering, it was missed that it needed to be the last thing in the series of lines.

Due to the order mismatch, I was getting false responses in the console out of order. If I placed the console before that line, the issue went away.

Easy to fix, once I was able to backtrack it, but it was odd how that simple ordering change was confusing the console output. New people looking at the code could easily add new lines after line 51, leading order data order issues, what looks like data corruption, and the like.

So, it just comes down to making sure the core loop actually contained everything inside of it.

Thanks for asking, I forgot about this thread.

@darkguy2008
Copy link
Author

Well this is interesting, I'm glad I've helped a lot of people with this gist, honestly I never thought it'd get so much attention haha, it was more like a way to show others how to make a simple client/server and also as a guide for me in case I forgot how to, for future projects haha.

UDP actually works in a way that packets won't come in order, always. That's why it's UDP. With TCP you have that guarantee, which is why it's a bit slower than UDP too. However, if there's indeed a fix for the code, let me know, if you can post a fixed version I can update the first gist so we all can benefit.

Thanks!

@louis-e
Copy link

louis-e commented Jul 22, 2019

Can anyone help me how to close this server correctly, so I can start him again? I tried s1._socket.Dispose();, s1._socket.Disconnect(true);, s1._socket.Close(); and always when I want to start the server again, it drops runtime errors.

I am grateful for any kind of help,
Louis

@louis-e
Copy link

louis-e commented Jul 23, 2019

Okay, I found the bug and I fixed it in a fork of your Gist.
https://gist.github.com/louis-e/888d5031190408775ad130dde353e0fd

@ishankapur
Copy link

thank you man! you are a legend...

@flameleo11
Copy link

good job

@MaxiCamilo
Copy link

Perfect, thank you!

@renanliberato
Copy link

Awesome!! Thank you!!

@DimaRichMain
Copy link

Not bad, smart concept

@JoshuaDoes
Copy link

I'm sorry if this is a really dumb question, I'm relatively new to writing C# from scratch (I normally just edit preexisting code to fix issues and patch functionality), but would my receive data handler have to go inside of this class's Receive method? Or is there a way for me to have Receive return a new packet if it finds one or return an empty byte array if it doesn't? Due to my functional programming background I'd rather do the latter

@SchneiderJonathan
Copy link

@JoshuaDoes : If you want to acsess the received data from outside i would suggest using an event callback (thats what i did, @op thanks for the code btw). Therefore you need to define the delegate public delegate void UdpOnReceived(byte[] data, int bytesRead); should add the public field public event UdpOnReceived OnReceived; to the UDPSocket-Class and add OnReceived?.Invoke(state.buffer, bytes); to the Receive function.
Now you would be able to attach a listener from outside to the Class like var socket = new UDPSocket(); //...blablabla... socket.OnReceived += MyReactionFunction;. Then you could play with your data inside of those MyReactionFunctions.

@ReedTrev
Copy link

@SchneiderJonathan great idea! And thanks @darkguy2008 and @louis-e for the code and edits!

@JoshuaDoes
Copy link

Thank you for the event callback idea @SchneiderJonathan, much appreciated!

@techtematy
Copy link

Is there a way to send from server back to client?

@louis-e
Copy link

louis-e commented Dec 8, 2020

Is there a way to send from server back to client?

Declare a client on the servers code and connect him to the loopback ip address.

@CoderOfTomorrow
Copy link

Is there a way to send from server back to client?

Declare a client on the servers code and connect him to the loopback ip address.

Can you give an example ^^

@louis-e
Copy link

louis-e commented Feb 14, 2021

You basically just have to declare a new client (in addition to the server and the already existing clients):
UDPSocket c = new UDPSocket();
Then you connect your just new declared client to your server (I assumed that the server runs on localhost and port 27000)
c.Client("127.0.0.1", 27000);
After that you can send your message over this new declared client to the other clients.
c.Send("TEST!");

@JohnStabler
Copy link

Important Note: Using UDP over Internet

I used this code as part of a multiplayer game server component. It worked fine once I added a SendTo() method for the server sending to clients. However, once I moved from testing on LAN to over the Internet I had issues. I had a static IP for my router and set up port forwarding. Was receiving UDP packets from clients, but any responses back to clients were disappearing. However, I removed the line:

_socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.ReuseAddress, true);

And it started working over Internet too.

@DavidK1968
Copy link

This works for me locally but when I send to a remote host I don't receive anything even though Wireshark shows the data coming back correctly from the remote host.

UDPSocket s = new UDPSocket();
s.Server("127.0.0.1", 2000);//binds to the local endpoint

UDPSocket c = new UDPSocket();
c.Client("192.168.26.186", 1999);//connects to the remote host

c.Send("0500020a04");

Summary from Wireshark:
image

Any ideas why?

@louis-e
Copy link

louis-e commented Apr 9, 2021

Assuming your remote host is in your local network; You have to use your local ip address (192.168.x.x) instead of the localhost 127.0.0.1 in your server declaration line (s.Server("127.0.0.1", 2000);). In addition to that you also have to use the same port for both server and client (e.g. 2000) 👍

@DavidK1968
Copy link

Assuming your remote host is in your local network; You have to use your local ip address (192.168.x.x) instead of the localhost 127.0.0.1 in your server declaration line (s.Server("127.0.0.1", 2000);). In addition to that you also have to use the same port for both server and client (e.g. 2000) 👍

Thanks for responding louis-e.

The remote host is in the local network so I am working with local Server 192.168.30.200 and remote Client 192.168.26.186. The client is a piece of industrial hardware that only receives on port 1999 and sends to port 2000 so I can't use the same port number. I proved correct communication using Packet Sender.

Perhaps I am going about this wrong. I am sending UDP successfully. As you can see from the Wireshark screen shot, the device is responding correctly to port 2000 of the local Server. I just am not receiving the data.

What is a better approach to receive the UDP from port 2000?

@louis-e
Copy link

louis-e commented Apr 10, 2021

Okay, I understand. Did you try to use s.Server("192.168.30.200", 2000); for declaring the server?

@DavidK1968
Copy link

That was it. I thought I has tried that but I guess not. It works now. Thanks so much!

@nm-hoang
Copy link

Thanks a lot! , It works fluently in my project

@jenya7
Copy link

jenya7 commented Jun 29, 2021

Thank you. Can you do it for TCP?

@jenya7
Copy link

jenya7 commented Jun 29, 2021

s.Server("127.0.0.1", 27000);
It's a local IP or remote? What if I don't know a remote IP? I want to receive from any socket.

@MrAladross
Copy link

Thanks! I was looking for a good example of UDP and this is a nice starting point.

@Neox2018
Copy link

Neox2018 commented Apr 1, 2022

Is it suppose to work easily ? I'm new with that client/servers code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment