-
-
Save darkguy2008/413a6fea3a5b4e67e5e0d96f750088a9 to your computer and use it in GitHub Desktop.
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(); | |
} | |
} | |
} |
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.
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!
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
Okay, I found the bug and I fixed it in a fork of your Gist.
https://gist.github.com/louis-e/888d5031190408775ad130dde353e0fd
thank you man! you are a legend...
good job
Perfect, thank you!
Awesome!! Thank you!!
Not bad, smart concept
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
@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.
@SchneiderJonathan great idea! And thanks @darkguy2008 and @louis-e for the code and edits!
Thank you for the event callback idea @SchneiderJonathan, much appreciated!
Is there a way to send from server back to client?
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.
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 ^^
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!");
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.
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");
Any ideas why?
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) 👍
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?
Okay, I understand. Did you try to use s.Server("192.168.30.200", 2000);
for declaring the server?
That was it. I thought I has tried that but I guess not. It works now. Thanks so much!
Thanks a lot! , It works fluently in my project
Thank you. Can you do it for TCP?
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.
Thanks! I was looking for a good example of UDP and this is a nice starting point.
Is it suppose to work easily ? I'm new with that client/servers code.
How to send a full file or image that sized 0.6mb or 600kb
@FoolishFrost How would you suggest the code be improved?