I am writing a mono C# application that needs to use UDP. I was writing my test suite so that I could make sure packets are received properly with NUnit.
I made a minimal working example with a UdpCom class that is supposed to just listen right now and print out the bytes it receives in the call back method.
My minimal UdpCom class looks like:
using System;
using System.Net;
using System.Net.Sockets;
namespace UdpPractice
{
public class UdpState
{
public UdpClient client;
public IPEndPoint endpoint;
public UdpState(UdpClient c, IPEndPoint iep)
{
this.client = c;
this.endpoint = iep;
}
}
public class UdpCom
{
public UdpState uState;
public UdpClient uClient;
public IPAddress address;
public int port;
public IPEndPoint uEndpoint;
public UdpCom (IPAddress address, int port)
{
uEndpoint = new IPEndPoint (address, port);
uClient = new UdpClient (uEndpoint);
uState = new UdpState (uClient, uEndpoint);
uClient.BeginReceive (new AsyncCallback(RxCallback), uState);
}
public void RxCallback(IAsyncResult result)
{
UdpState rState = (UdpState)(result.AsyncState);
UdpClient rClient = rState.client;
IPEndPoint rEndPoint = rState.endpoint;
byte[] rxBytes = rClient.EndReceive (result, ref rEndPoint);
Console.WriteLine ("Received Bytes ___________________________");
Console.WriteLine (rxBytes.ToString ());
rClient.BeginReceive (new AsyncCallback(RxCallback), rState);
}
}
}
My simple test instantiates this class and then sends it a dummy packet of bytes. I am not testing the result right now, just placing a break point in my RxCallback method.
This is my NUNIT test:
using NUnit.Framework;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UdpPractice;
namespace UdpTest
{
[TestFixture ()]
public class Test
{
[Test ()]
public void TestCase ()
{
// Setup Receiver
IPAddress address = new IPAddress (new byte[] { 127, 0, 0, 1 });
int port = 14580;
UdpCom com = new UdpCom (address, port);
com.uClient.Connect (com.uEndpoint);
// Set up sender
UdpClient sender = new UdpClient(new IPEndPoint (address, port));
sender.Connect (address, port);
// Dummy Data
byte [] dummyData = new byte[] {1, 2, 3, 4, 4, 5};
sender.Send (dummyData, dummyData.Length);
Thread.Sleep (100);
// Close
sender.Close ();
com.uClient.Close ();
}
}
}
My Issue is that when I'm in the RxCallback method on the line that I'm trying to retrieve the bytes I am getting this exception:
System.ObjectDisposedException has been thrown
Cannot access a disposed object.
Object name: System.Net.Sockets.UdpClient
I want to be able to store these bytes in a queue in my UdpCom class but I am having trouble accessing them in the first place.
I may be failing to udner stand some basic UDP concepts as well here but it seems pretty straght forward.
The udp examples I have been following are:
https://yal.cc/cs-dotnet-asynchronous-udp-example/
https://www.codeproject.com/articles/132623/basic-udp-receiver
EDIT
I updated my class and tests as follows so I don't use the local loopback. But I am still getting the same exception.
UdpCom is now:
using System;
using System.Net;
using System.Net.Sockets;
namespace UdpPractice
{
public class UdpState
{
public UdpClient client;
public IPEndPoint endpoint;
public UdpState(UdpClient c, IPEndPoint iep)
{
this.client = c;
this.endpoint = iep;
}
}
public class UdpCom
{
public UdpState uState;
public UdpClient uClient;
public IPAddress address;
public int port;
public IPEndPoint uEndpoint;
public UdpCom (IPAddress address, int port)
{
uEndpoint = new IPEndPoint (address, port);
uClient = new UdpClient (uEndpoint);
uState = new UdpState (uClient, uEndpoint);
uClient.BeginReceive (new AsyncCallback(RxCallback), uState);
}
public void RxCallback(IAsyncResult result)
{
UdpState rState = (UdpState)(result.AsyncState);
UdpClient rClient = rState.client;
IPEndPoint rEndPoint = rState.endpoint;
byte[] rxBytes = rClient.EndReceive (result, ref rEndPoint);
Console.WriteLine ("Received Bytes ___________________________");
Console.WriteLine (rxBytes.ToString ());
rClient.BeginReceive (new AsyncCallback(RxCallback), rState);
}
}
}
and the test is:
using NUnit.Framework;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UdpPractice;
namespace UdpTest
{
[TestFixture ()]
public class Test
{
[Test ()]
public void TestCase ()
{
// Setup Receiver
IPAddress address = new IPAddress (new byte[] { 192, 168, 1, 161 });
int port = 14580;
UdpCom com = new UdpCom (IPAddress.Any, port);
// com.uClient.Connect (com.uEndpoint);
// Set up sender
UdpClient sender = new UdpClient(new IPEndPoint (address, port));
sender.Connect (address, port);
// Dummy Data
byte [] dummyData = new byte[] {1, 2, 3, 4, 4, 5};
sender.Send (dummyData, dummyData.Length);
Thread.Sleep (100);
// Close
sender.Close ();
com.uClient.Close ();
}
}
}
I guess I was struggling with a basic misunderstanding with how to communicate with UDP.
UdpCom:
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
namespace UdpPractice
{
public class UdpState
{
public UdpClient client;
public IPEndPoint endpoint;
public UdpState(UdpClient c, IPEndPoint iep)
{
this.client = c;
this.endpoint = iep;
}
}
public class UdpCom
{
public UdpState uState;
public IPAddress address;
public int port;
public IPEndPoint uEndpoint;
public bool receiveFlag;
public List<byte[]> rxBytesBuffer;
public UdpCom (IPAddress address, int port)
{
uEndpoint = new IPEndPoint (address, port);
// uClient = new UdpClient (uEndpoint);
uState = new UdpState (new UdpClient(new IPEndPoint(IPAddress.Parse("127.0.0.1"), port)), uEndpoint);
receiveFlag = false;
uState.client.BeginReceive (new AsyncCallback(RxCallback), uState);
rxBytesBuffer = new List<byte[]> ();
}
public void RxCallback(IAsyncResult result)
{
UdpState rState = (UdpState)result.AsyncState;
UdpClient rClient = ((UdpState)result.AsyncState).client;
IPEndPoint rEndPoint = ((UdpState)result.AsyncState).endpoint;
byte[] rxBytes = rClient.EndReceive (result, ref rEndPoint);
rxBytesBuffer.Add (rxBytes);
Console.WriteLine ("Received Bytes ___________________________");
Console.WriteLine (rxBytes.ToString ());
receiveFlag = true;
rClient.BeginReceive (new AsyncCallback(RxCallback), result.AsyncState);
}
}
}
Test:
using NUnit.Framework;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UdpPractice;
namespace UdpTest
{
[TestFixture ()]
public class Test
{
[Test ()]
public void TestCase ()
{
// Setup Listener
int port = 14580;
IPEndPoint locep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), port);
// Server (Listener)
UdpCom com = new UdpCom (IPAddress.Any, port);
// Set up sender
UdpClient sender = new UdpClient();
// Dummy Data
byte [] dummyData = new byte[] {1, 2, 3, 4, 4, 5};
sender.Send (dummyData, dummyData.Length, locep);
sender.Send (dummyData, dummyData.Length, locep);
Thread.Sleep (100);
Assert.AreEqual(true, com.receiveFlag);
}
}
}
I needed to make the listener listen to IPAddress.Any and then I mainly used the Send method with the EndPoint argument. I had to add the delay in there because otherwise the receive flag wasn't being set.
Related
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace PowerCarsMobileServer
{
class Server
{
public static int Port { get; private set; }
private static TcpListener tcpListener;
public static ServerSocket serverSocket; //problem is here
public static void Start(int _port)
{
Port = _port;
serverSocket = new ServerSocket(Port);
Console.WriteLine("Starting server...");
InitializeServerData();
tcpListener = new TcpListener(IPAddress.Any, Port);
tcpListener.Start();
Console.WriteLine($"Server started on {Port}.");
}
}
}
When creating a global port, I ran into the problem of not supporting "ServerSocket". Older articles use ServerSocket but I don't understand the problem comparing my code with theirs.
How can I fix it?
I tried to connect different references, but it doesn't work or I didn't find a good one
It's for a multiplayer video game:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
namespace ShootingMasters
{
public class Communicator
{
public UdpClient client;
public IPAddress toconnectto;
public Communicator(IPAddress toconnectto)
{
this.toconnectto = toconnectto;
client = new UdpClient();
client.Connect(toconnectto, 25565);
}
public void SendData(string data)
{
byte[] bdata = ASCIIEncoding.ASCII.GetBytes(data);
IPEndPoint iP = new IPEndPoint(toconnectto, 25565);
try
{
client.Send(bdata, bdata.Length);
}
catch(Exception e)
{
}
}
public string RecData()
{
if (client.Available > 0)
{
try
{
IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Any, 25565);
byte[] data = client.Receive(ref iPEndPoint);
return ASCIIEncoding.ASCII.GetString(data);
}
catch(Exception e)
{
return null;
}
}
else
{
return null;
}
}
}
}
When you call receive, it returns null because an exception was thrown. The exception message was
An existing connection was forcibly closed by the remote host
Also, inside receive client.Available is 1 then right after an exception is thrown, it is 0.
i am using those scripts bellow to send and receive data, when i send data from an android support to my computer i can't receive anything !!! i can't find the problem can anyone help me please
using UnityEngine;
using System.Collections;
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
public class UDPSend : MonoBehaviour
{
public string IP = "myIP"; // default local
public int port = 26000;
IPEndPoint remoteEndPoint;
UdpClient client;
string strMessage="";
public void Start()
{
init();
}
void OnGUI()
{
Rect rectObj=new Rect(40,380,200,400);
GUIStyle style = new GUIStyle();
style.alignment = TextAnchor.UpperLeft;
GUI.Box(rectObj,"UDPSendData\n IP : "+IP+" Port : "+port,style);
//
strMessage=GUI.TextField(new Rect(40,420,140,20),strMessage);
if (GUI.Button(new Rect(190,420,40,20),"Send"))
{
sendString(strMessage+"\n");
}
}
// init
public void init()
{
IP="myIP";
port=26000; // quake port ;)
remoteEndPoint = new IPEndPoint(IPAddress.Parse(IP), port);
//remoteEndPoint = new IPEndPoint(IPAddress.Broadcast, port); // toute machine
client = new UdpClient();
}
// sendData
private void sendString(string message)
{
try
{
byte[] data = Encoding.UTF8.GetBytes(message);
client.Send(data, data.Length, remoteEndPoint);
}
catch (Exception err)
{
print(err.ToString());
}
}
void OnDisable()
{
if ( client!= null) client.Close();
}
}
UDPReceive:
using UnityEngine;
using System.Collections;
using System;
using System.Net;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net.NetworkInformation;
public class UDPReceive : MonoBehaviour {
Thread receiveThread;
UdpClient client;
public int port = 26000;
string strReceiveUDP="";
string LocalIP = String.Empty;
string hostname;
public void Start()
{
Application.runInBackground = true;
init();
}
// init
private void init()
{
receiveThread = new Thread( new ThreadStart(ReceiveData));
receiveThread.IsBackground = true;
receiveThread.Start();
hostname = Dns.GetHostName();
IPAddress[] ips = Dns.GetHostAddresses(hostname);
if (ips.Length > 0)
{
LocalIP = ips[0].ToString();
}
}
void OnGUI()
{
Rect rectObj=new Rect(10,10,400,200);
GUIStyle style = new GUIStyle();
style.alignment = TextAnchor.UpperLeft;
GUI.Box(rectObj,hostname+" MY IP : "+LocalIP+" : "+strReceiveUDP,style);
}
private void ReceiveData()
{
client = new UdpClient(port);
while (true)
{
try
{
IPEndPoint anyIP = new IPEndPoint(IPAddress.Broadcast, port);
//IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
byte[] data = client.Receive(ref anyIP);
string text = Encoding.UTF8.GetString(data);
strReceiveUDP = text;
//Debug.Log(strReceiveUDP);
}
catch (Exception err)
{
print(err.ToString());
}
}
}
public string UDPGetPacket()
{
return strReceiveUDP;
}
void OnDisable()
{
if ( receiveThread!= null) receiveThread.Abort();
client.Close();
}
}
When myIP is 127.0.0.1 everything works normally
I'm creating a C# socket for UDP receive and send capabilities with Asynchronous callback functions for the receive. Simple, right! It took a while to get all the wrinkles ironed out, but it works... Well, as long as you hog the port! I need to allow other applications to use the same port number. No problem, right! There's an option for that, SetSocketOption(...) for ReuseAddress...
udpClient.SetSocketOption(SocketOptionLevel.Udp, SocketOptionName.ReuseAddress, true);
Why is it that when I set ReuseAddress to true, the callback function doesn't get hit anymore?
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using CSharpUtilityLibrary.Utilities;
namespace CSharpNIU.Sockets
{
public class PacketEventArgs : EventArgs {
public byte[] Bytes { get; set; }
public PacketEventArgs(byte[] bytes)
{
Bytes = bytes;
}
}
public delegate void PacketEventHandler(object sender, PacketEventArgs e);
// State object for reading client data asynchronously
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1553;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
}
public class UDPSocket
{
// Thread signal.
public ManualResetEvent allDone = new ManualResetEvent(false);
public String ApplicationName { get; set; }
public Form ParentForm { get; set; }
public Network ApplicationNetwork { get; set; }
private ConfigGeneric Config { get; set; }
private Socket udpClient = null;
public UDPSocket(ConfigGeneric config, String applicationName)
{
Config = config;
ApplicationDetails appDetails = config.GetApplicationByName(applicationName);
if (appDetails == null)
return;
ApplicationNetwork = config.GetNetworkByName(appDetails._network);
if (ApplicationNetwork == null) return;
}
public void StartListening()
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
IPAddress ipAddress = IPAddress.Parse(ApplicationNetwork._networkAddress);
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, ApplicationNetwork._receivePort);
// Create a UDP Socket
udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// Bind the socket to the local endpoint
try
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
allDone.Set();
StateObject stateObject = new StateObject();
stateObject.workSocket = udpClient;
//------> The line Below causes the begin receive to not call ReadCallback <-------//
udpClient.SetSocketOption(SocketOptionLevel.Udp, SocketOptionName.ReuseAddress, true);
//------> The line Above causes the begin receive to not call ReadCallback <-------//
udpClient.Bind(localEndPoint);
udpClient.BeginReceive(stateObject.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReadCallback), stateObject);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
// Retrieve the state object and the handler socket from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
PacketEventArgs packetEventArgs = new PacketEventArgs(state.buffer);
OnRecevedPacket(packetEventArgs);
// There might be more data, so store the data received so far.
udpClient.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReadCallback), state);
}
}
// Event Handlers
public event PacketEventHandler ReceiveCallback;
protected virtual void OnRecevedPacket(PacketEventArgs e)
{
if (ReceiveCallback != null)
ReceiveCallback(this, e);
}
public void Send(byte[] bytes)
{
// Begin sending the data to the remote device.
IPAddress ipAddress = IPAddress.Parse(ApplicationNetwork._broadcastAddress);
IPEndPoint endPoint = new IPEndPoint(ipAddress, ApplicationNetwork._receivePort);
udpClient.SendTo(bytes, endPoint);
}
}
}
From what I can tell, you should be using UdpClient instead of going low level with Socket.
You also need to create UdpClient with the default constructor to be able to change settings like ExclusiveAddressUse.
This guy has a working example: http://social.msdn.microsoft.com/Forums/en-US/fe830c54-30ab-4ae6-a86a-7c2a9ccd11cf/udpclient-more-than-one-on-the-same-port
I have this very weird error. Basically, as soon as I add the line of code Connections.Add(handler); my program goes haywire. I'm also getting the error:
System.OutOfMemoryException: Exception of type
'System.OutOfMemoryException' was thrown. at
System.Threading.ExecutionContext.CreateCopy() at
System.Net.ContextAwareResult.CaptureOrComplete(ExecutionContext&
cachedContext, Boolean returnContext)
What happens is, when I add this code, connections are still being accepted, but nothing is being logged on my log richtextbox control. This is very weird, and I have no idea whats going on. However, removing that Connections.Add(handler) line in my accept event solves all problems. But I need to keep track of sockets somehow so I can implement pinging to keep them alive
Here is my code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections.Concurrent;
namespace SpybotServer
{
public partial class Server : Form
{
public void log(String text)
{
logs.InvokeEx(a => a.Text += (text +Environment.NewLine));
}
public Server()
{
InitializeComponent();
}
private void Server_Load(object sender, EventArgs e)
{
Thread serverThread = new Thread(delegate()
{
Listener.StartListening(9001);
});
serverThread.Start();
heartbeat.Start();
}
private void Server_FormClosed(object sender, FormClosedEventArgs e)
{
Listener.looping = false;
}
private void heartbeat_Tick(object sender, EventArgs e)
{
Listener.heartbeat();
}
}
public class StateObject
{
public Socket workSocket = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
public StringBuilder sb = new StringBuilder();
}
public class Listener
{
public static Boolean looping = true;
private static List<Socket> Connections = new List<Socket>();
public static void heartbeat()
{
Program.MainForm.log("Sending ping...");
}
public static void StartListening(int port)
{
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 9001);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Program.MainForm.log("Listening on port " + port);
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (looping)
{
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
}
}
catch (Exception e)
{
Program.MainForm.log(e.ToString());
}
}
public static void AcceptCallback(IAsyncResult ar)
{
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
StateObject state = new StateObject();
state.workSocket = handler;
IPEndPoint ip = handler.RemoteEndPoint as IPEndPoint;
Program.MainForm.log("Accepted connection from " + ip.Address);
//Connections.Add(handler);
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
StateObject state = (StateObject) ar.AsyncState;
Socket handler = state.workSocket;
try
{
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
state.sb.Append(Encoding.ASCII.GetString(
state.buffer, 0, bytesRead));
content = state.sb.ToString();
/*if (content.IndexOf("!#<EOF_END>#!") > -1)
{
Program.MainForm.log(content);
}
else
{
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}*/
}
}
catch (Exception e)
{
Program.MainForm.log(e.ToString());
}
}
private static void Send(Socket handler, String data)
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
handler.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar)
{
Socket handler = (Socket)ar.AsyncState;
try
{
int bytesSent = handler.EndSend(ar);
if (bytesSent <= 0)
{
Program.MainForm.log("Socket has been closed.");
}
}
catch (Exception e)
{
Program.MainForm.log(e.ToString());
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
}
}
}
InvokeEx:
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace SpybotServer
{
static class ISynchronizeInvokeExtensions
{
public static void InvokeEx<T>(this T #this, Action<T> action) where T : ISynchronizeInvoke
{
if (#this.InvokeRequired)
{
#this.Invoke(action, new object[] { #this });
}
else
{
action(#this);
}
}
}
}
Since this callback:
public static void AcceptCallback(IAsyncResult ar)
is inside this loop:
while (looping)
{
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
}
I'm more than 90% certain that you are adding the same Socket to the Connections list over and over and just growing the size of the list at an alarming rate. Change the add to this:
if (Connections.Contains(handler))
{
Connections.Add(handler);
}
Michael is on the right track, but not with the right solution.
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
Is (unlike Accept) not going to block and weird things are going to happen if you call it this way. Instead take your BeginAccept out of a loop and call it again from AcceptCallback so that you can accept a new connection after you have accepted a first.