I am trying to find Lantronix XPort Pro devices on a network using C#. I am using some python code that I found on the Lantronix developer wiki as an example http://wiki.lantronix.com/developer/Lantronix_Discovery_Protocol.
The application I am writing is written in C# and I need to discover our units that have Lantronix devices installed. It seems that when I do the socket.RecieveFrom function call it just seems to hang the app.
Any ideas on what I am doing wrong. The python code from the link above detects the devices correctly. I should be able to duplicate this in C#.
Any help would be much appreciated.
private void FindLantronixXPort()
{
// This is the socket code that will broadcast from
// the local machine looking for responces from Lantronix
// XPort servers
// Create the array for our message chars
char[] chars = new char[4];
// Build the actual message
chars[0] = Convert.ToChar(0);
chars[1] = Convert.ToChar(0);
chars[2] = Convert.ToChar(0);
chars[3] = Convert.ToChar(0xf6);
// Convert the chars to a message string
string msg = new string(chars);
// Convert the setring to a byte array
byte[] data = Encoding.UTF8.GetBytes(msg);
// Get the local machines IP address
string Local_IP = GetIPAddress();
// Now create a broadcast UDP socket
Socket XmtSock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
XmtSock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
IPEndPoint iep = new IPEndPoint(IPAddress.Parse(Local_IP), LantronixPort);
// Broadcast the packet
XmtSock.SendTo(data, 0, data.Length, SocketFlags.None, iep);
XmtSock.Close();
// Wait 500 mili seconds
int milliseconds = 500;
System.Threading.Thread.Sleep(milliseconds);
Socket RcvSock = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp);
iep = new IPEndPoint(IPAddress.Any, LantronixPort);
RcvSock.Bind(iep);
EndPoint ep = (EndPoint)iep;
Console.WriteLine("Ready to receive...");
byte[] data1 = new byte[120];
int recv = RcvSock.ReceiveFrom(data1, data1.Length, SocketFlags.None, ref ep);
string stringData = Encoding.ASCII.GetString(data1, 0, recv);
Console.WriteLine("received: {0} from: {1}",
stringData, ep.ToString());
RcvSock.Close();
}
Lantronix's wiki seems to be down at the moment, so I can't take a look at that for the moment. However, looking at your code it seems that you have to broadcast a UDP message, wait some time, and then check to see if anything has responded to that message.
However, it looks like you're creating a brand new socket for receiving the responses, but only after half a second. It's highly likely that any X-port that is going to respond will already have done so long before then (networks are fast, X-ports aren't very sluggish, etc). So I reckon the responses are hitting your OS'es network stack, which saying "well I dunno where that's supposed to go", and only after half a second are you creating a socket suitable for receiving the responses that the OS'es network stack has already discarded as unknown junk.
So move things around a bit is what I suggest. Set up the receiving socket, binding and endpoint before you transmit the broadcast message, so that it's ready there waiting for responses. See if that helps.
#WJD Your code for preparing byte array did not create content expected by XPort. It is why it did not replyed and hang on RecieveFrom().
I followed the link you gave for python example and created version in C#.
class Program
{
static void Main(string[] args)
{
Socket socket;
int GroupPort = 30718;
try
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
var localEP = new IPEndPoint(IPAddress.Parse("10.0.2.14"), GroupPort); // <-- your local IP address
socket.Bind(localEP);
socket.ReceiveTimeout = 200;
}
catch (TimeoutException e)
{
Console.WriteLine("Failed to create socket. " + e.Message);
return;
}
var remoteEP = new IPEndPoint(IPAddress.Broadcast, GroupPort);
try
{
byte[] messageBytes;
messageBytes = new byte[0];
messageBytes = AddByteToArray(messageBytes, 0xf6);
messageBytes = AddByteToArray(messageBytes, 0);
messageBytes = AddByteToArray(messageBytes, 0);
messageBytes = AddByteToArray(messageBytes, 0);
socket.SendTo(messageBytes, remoteEP);
}
catch (Exception e)
{
Console.WriteLine("Failed to send message. " + e.Message);
return;
}
var recvEp = (EndPoint)new IPEndPoint(IPAddress.Any, 0);
while (true)
{
try
{
var recvBytes = new byte[1024];
var receivedCount = socket.ReceiveFrom(recvBytes, ref recvEp);
var receivedArray = recvBytes.Take(receivedCount).ToArray();
var receivedArrayAsHexString = string.Join("", receivedArray.Select(c => String.Format("{0:X2}", Convert.ToInt32(c))));
string returnData = Encoding.ASCII.GetString(receivedArray);
Console.WriteLine($"Broadcast Respond from client {recvEp.ToString()} returned: {receivedArrayAsHexString}");
}
catch (Exception e)
{
socket.Close();
break;
}
}
Console.ReadLine();
}
public static byte[] AddByteToArray(byte[] bArray, byte newByte)
{
byte[] newArray = new byte[bArray.Length + 1];
bArray.CopyTo(newArray, 1);
newArray[0] = newByte;
return newArray;
}
}
Related
I am trying to send data to a server from my client .the client sends messages to a server ,every message is 36 bytes and in this message every 4 byte is a field and in server part i should be able to detect that field from the message that client sends .Suppose i have this data :
A=21
B=32
c=43
D=55
E=75
F=73
G=12
H=14
M=12
In the client i should send this values as a single message .as you can see my message has 9 field and every field is 4 byte integer and all message is 36 byte.
So in server part when the message is received i should be able to separate the message and find the value of the fields .
In client application i am using this structure to send message to my server :
m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Cet the remote IP address
IPAddress ip = IPAddress.Parse(GetIP());
int iPortNo = System.Convert.ToInt16("12345");
// Create the end point
IPEndPoint ipEnd = new IPEndPoint(ip, iPortNo);
// Connect to the remote host
m_clientSocket.Connect(ipEnd);
if (m_clientSocket.Connected)
{
Object objData = ?!!!!;//My message
byte[] byData = System.Text.Encoding.ASCII.GetBytes(objData.ToString());
if (m_clientSocket != null)
{
m_clientSocket.Send(byData);
}
Thread.Sleep(4000);
}
}
And in server part i am using this code to receive the data:
public void OnDataReceived(IAsyncResult asyn)
{
try
{
SocketPacket socketData = (SocketPacket)asyn.AsyncState;
int iRx = 0;
// Complete the BeginReceive() asynchronous call by EndReceive() method
// which will return the number of characters written to the stream
// by the client
iRx = socketData.m_currentSocket.EndReceive(asyn);
char[] chars = new char[iRx + 1];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
int charLen = d.GetChars(socketData.dataBuffer,
0, iRx, chars, 0);
System.String szData = new System.String(chars);
MessageBox.Show(szData);
// Continue the waiting for data on the Socket
WaitForData(socketData.m_currentSocket);
}
catch (ObjectDisposedException)
{
System.Diagnostics.Debugger.Log(0, "1", "\nOnDataReceived: Socket has been closed\n");
}
catch (SocketException se)
{
}
}
Here is the other part of my server code :
public void OnClientConnect(IAsyncResult asyn)
{
try
{
// Here we complete/end the BeginAccept() asynchronous call
// by calling EndAccept() - which returns the reference to
// a new Socket object
m_workerSocket[m_clientCount] = m_mainSocket.EndAccept(asyn);
// Let the worker Socket do the further processing for the
// just connected client
WaitForData(m_workerSocket[m_clientCount]);
// Now increment the client count
++m_clientCount;
// Display this client connection as a status message on the GUI
String str = String.Format("Client # {0} connected", m_clientCount);
// Since the main Socket is now free, it can go back and wait for
// other clients who are attempting to connect
m_mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
}
catch (ObjectDisposedException)
{
System.Diagnostics.Debugger.Log(0, "1", "\n OnClientConnection: Socket has been closed\n");
}
}
public class SocketPacket
{
public System.Net.Sockets.Socket m_currentSocket;
public byte[] dataBuffer = new byte[36];
}
In my form_load of server part i have this code:
ipaddress = GetIP();
// Check the port value
string portStr = "12345";
int port = System.Convert.ToInt32(portStr);
// Create the listening socket...
m_mainSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, port);
// Bind to local IP Address...
m_mainSocket.Bind(ipLocal);
// Start listening...
m_mainSocket.Listen(4);
// Create the call back for any client connections...
m_mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
in fact i am trying to implement this link :
http://www.codeguru.com/csharp/csharp/cs_misc/sampleprograms/article.php/c7695/Asynchronous-Socket-Programming-in-C-Part-I.htm
My problem is how can i send my message as a 36 bytes via client and get and separate that from server ?
Every four bytes is a field and i should be able to get this value .
You're doing it wrong. If you want to transmit binary data, do not encode it as a string. There are multiple ways to do this:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Msg
{
public int A, B, C, D, E, F, G, H, M;
}
Then use the Marshal class to get the bytes. This will get you little-endian on the wire data though.
Another method is to use a BinaryWriter. Same thing, little-endian data unless you convert it yourself or use an alternate version of BinaryWriter.
Then, it's much easier to use a NetworkStream, because this class will handle packet fragmentation for you. Here's the sending code using the BinaryWriter method:
using (var stream = new NetworkStream(stocket))
{
var writer = new BinaryWriter(stream);
writer.Write(21);
writer.Write(32);
// etc
}
Same thing on the client side using a NetworkStream and a BinaryReader.
NB: You can use async I/O with NetworkStream using the async/await feature.
Seems like all you need is 2 methods to convert integers to byte-array and vice versa:
byte[] packet = CreateMessage(21,32,43,55,75,73,12,14,12);
//send message
//recv message and get ints back
int[] ints = GetParameters(packet);
....
public byte[] CreateMessage(params int[] parameters)
{
var buf = new byte[parameters.Length * sizeof(int)];
for (int i = 0; i < parameters.Length; i++)
Array.Copy(BitConverter.GetBytes(parameters[i]), 0, buf, i * sizeof(int), sizeof(int));
return buf;
}
public int[] GetParameters(byte[] buf)
{
var ints = new int[buf.Length / sizeof(int)];
for (int i = 0; i < ints.Length; i++)
ints[i] = BitConverter.ToInt32(buf, i * sizeof(int));
return ints;
}
For some reason I am having a hard time sending and receiving data from the same socket. Anyways here is my client code:
var client = new UdpClient();
IPEndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 11000); // endpoint where server is listening (testing localy)
client.Connect(ep);
// send data
client.Send(new byte[] { 1, 2, 3, 4, 5 }, 5);
// then receive data
var receivedData = client.Receive(ref ep); // Exception: An existing connection was forcibly closed by the remote host
Basically I want to create a protocol where I send a udp packet and then I expect a response. Just like the HTTP protocol for every request there is a response. This code works if the server is on a different computer. There might be the case where the server and client are on the same computer though.
Here is the server:
UdpClient udpServer = new UdpClient(UDP_LISTEN_PORT);
while (true)
{
var groupEP = new IPEndPoint(IPAddress.Any, 11000); // listen on any port
var data = udpServer.Receive(ref groupEP);
udpServer.Send(new byte[] { 1 }, 1); // if data is received reply letting the client know that we got his data
}
Edit
the reason why I cannot use tcp is because sometimes the client is behind a NAT (router) and it is simpler to do UDP hole punching than TCP.
Solution:
thanks to markmnl answer here is my code:
Server:
UdpClient udpServer = new UdpClient(11000);
while (true)
{
var remoteEP = new IPEndPoint(IPAddress.Any, 11000);
var data = udpServer.Receive(ref remoteEP); // listen on port 11000
Console.Write("receive data from " + remoteEP.ToString());
udpServer.Send(new byte[] { 1 }, 1, remoteEP); // reply back
}
Client code:
var client = new UdpClient();
IPEndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 11000); // endpoint where server is listening
client.Connect(ep);
// send data
client.Send(new byte[] { 1, 2, 3, 4, 5 }, 5);
// then receive data
var receivedData = client.Receive(ref ep);
Console.Write("receive data from " + ep.ToString());
Console.Read();
(I presume you are aware that using UDP(User Datagram Protocol) does not guarantee delivery, checks for duplicates and congestion control and will just answer your question).
In your server this line:
var data = udpServer.Receive(ref groupEP);
re-assigns groupEP from what you had to a the address you receive something on.
This line:
udpServer.Send(new byte[] { 1 }, 1);
Will not work since you have not specified who to send the data to. (It works on your client because you called connect which means send will always be sent to the end point you connected to, of course we don't want that on the server as we could have many clients). I would:
UdpClient udpServer = new UdpClient(UDP_LISTEN_PORT);
while (true)
{
var remoteEP = new IPEndPoint(IPAddress.Any, 11000);
var data = udpServer.Receive(ref remoteEP);
udpServer.Send(new byte[] { 1 }, 1, remoteEP); // if data is received reply letting the client know that we got his data
}
Also if you have server and client on the same machine you should have them on different ports.
I'll try to keep this short, I've done this a few months ago for a game I was trying to build, it does a UDP "Client-Server" connection that acts like TCP, you can send (message) (message + object) using this. I've done some testing with it and it works just fine, feel free to modify it if needed.
here is my soln to define the remote and local port and then write out to a file the received data, put this all in a class of your choice with the correct imports
static UdpClient sendClient = new UdpClient();
static int localPort = 49999;
static int remotePort = 49000;
static IPEndPoint localEP = new IPEndPoint(IPAddress.Any, localPort);
static IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), remotePort);
static string logPath = System.AppDomain.CurrentDomain.BaseDirectory + "/recvd.txt";
static System.IO.StreamWriter fw = new System.IO.StreamWriter(logPath, true);
private static void initStuff()
{
fw.AutoFlush = true;
sendClient.ExclusiveAddressUse = false;
sendClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
sendClient.Client.Bind(localEP);
sendClient.BeginReceive(DataReceived, sendClient);
}
private static void DataReceived(IAsyncResult ar)
{
UdpClient c = (UdpClient)ar.AsyncState;
IPEndPoint receivedIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
Byte[] receivedBytes = c.EndReceive(ar, ref receivedIpEndPoint);
fw.WriteLine(DateTime.Now.ToString("HH:mm:ss.ff tt") + " (" + receivedBytes.Length + " bytes)");
c.BeginReceive(DataReceived, ar.AsyncState);
}
static void Main(string[] args)
{
initStuff();
byte[] emptyByte = {};
sendClient.Send(emptyByte, emptyByte.Length, remoteEP);
}
Here's my problem; I'm trying to make a UDP server - client interaction as a test. I want the client to send data to the server, and if the server matches data the server holds, it sends a reply. Simple, right? Here's some code:
Client send/receive code:
void TestUDP()
{
Socket sock_addr = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint srver_endpoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 36);
string numbers = "1.2.3.4";
byte[] srver_req = Encoding.UTF8.GetBytes("TEST|" + numbers);
sock_addr.SendTo(srver_req, srver_endpoint);
EndPoint ref_endpoint = (EndPoint)srver_endpoint;
byte[] req_reply = new byte[1000];
sock_addr.ReceiveFrom(req_reply, ref ref_endpoint);
string reply = Encoding.UTF8.GetString(req_reply).Trim();
string[] s_str = reply.Split('|');
if (s_str[0] == "HEY")
{
MessageBox.Show("HEY");
}
else
{
MessageBox.Show("NO");
}
}
Now some server code:
public void start()
{
udp_sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
udp_sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
udp_thr = new Thread(udpListen);
udp_thr.Start();
}
void udpListen()
{
byte[] data = new byte[1024];
IPEndPoint ip = new IPEndPoint(IPAddress.Any, 36);
udp_sock.Bind(ip);
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint Remote = (EndPoint)(sender);
while (true)
{
udp_sock.ReceiveFrom(data, ref Remote);
Parse(data, Remote);
}
}
void Parse(byte[] data, EndPoint Remote)
{
string decData = Encoding.UTF8.GetString(data).Trim();
string[] s_str = decData.Split('|');
byte[] sendBuffer = new byte[] { };
switch (s_str[0])
{
case "TEST":
string data1 = s_str[1];
if (data1 == "1.2.3.4")
{
sendBuffer = Encoding.UTF8.GetBytes("HEY|");
}
else if(data1 != "1.2.3.4")
{
sendBuffer = Encoding.UTF8.GetBytes("NO|");
}
udp_sock.SendTo(sendBuffer, Remote);
break;
}
}
Now the issue is, it ALWAYS says "NO", I have no idea why. To me this looks like it should work, what am I doing wrong??
I've put this socket onto Broadcast, because I'd also like to handle Broadcast requests with this too. Is that a problem?
Firstly, you should add diagnostics to print out the actual data rather than just knowing that it's "right" or "wrong".
Next, the actual problem is that you're ignoring the result of udp_sock.ReceiveFrom. That will tell you how many bytes have actually been received. Currently, you're always converting all 1024 bytes into a string... which means you're likely to have trailing data which you haven't just received. Just using Trim() isn't a good way of countering that. Trim() doesn't count U+0000 as whitespace, and even if it did it still wouldn't be an appropriate approach - aside from anything else, you're reusing the same buffer later, so if you received a long message and then a shorter one, you'd end up with a mixture.
You want:
// TODO: Fix your variable names, which are inconsistent non-idiomatic
int bytesRead = udp_sock.ReceiveFrom(data, ref Remote);
Parse(data, bytesRead, Remote);
and change Parse to:
void Parse(byte[] data, int bytesRead, EndPoint remote)
{
string text = Encoding.UTF8.GetString(data, 0, bytesRead);
...
}
You need to do that on both the client and the server.
Also, given that the first branch of the if/else checks whether data1 is "1.2.3.4", you don't need to then check that it isn't.
I've been searching for previous problems like mine here but it seems I can't find the answer I need.
My goal is to prevent my UDP listener from not hanging. I have a UDP listener who waits for messages but if there is nothing to receive it just hangs there.
I have read other threads and they say that I need to set the Blocking to false but I can't find how to set it. Sorry I'm just new to C# and to socket programming.
Here's the part of my listener:
while (true)
{
try
{
byte[] data = listener.Receive(ref groupEP);
IPEndPoint newuser = new IPEndPoint(groupEP.Address, groupEP.Port);
string sData = (System.Text.Encoding.ASCII.GetString(data));
}
catch (Exception e)
{
}
}
My problem is it just freezes on the following line:
byte[] data = listener.Receive(ref groupEP);
Use the available property on the UDPClient (if this is what you are using) to determine if you have data in the network queue to read.
while (true)
{
try
{
if (listener.Available > 0) // Only read if we have some data
{ // queued in the network buffer.
byte[] data = listener.Receive(ref groupEP);
IPEndPoint newuser = new IPEndPoint(groupEP.Address, groupEP.Port);
string sData = (System.Text.Encoding.ASCII.GetString(data));
}
}
catch (Exception e)
{
}
}
UdpClient client = new UdpClient();
//Some code goes here ...
client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 2000);
//This is pretty clear and simple.
You are using the blocking versions of Receive/Send. Consider using the async versions (ReceiveAsync/BeginReceive) instead.
https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.udpclient?view=netcore-3.1
TestHost.Client.Blocking = false;
You need to access the 'Socket' object, beneath the UdpClient object ('TestHost' in the detailed example below), to get to the 'Blocking' property as shown:
int Port = 9020; //Any port number you like will do
IPAddress ActiveIPaddress = new IPAddress(new byte[] { 192, 168, 3, 10 }); //Any IPaddress you need will do
IPEndPoint HostEP = new IPEndPoint(ActiveIPaddress, Port);
UdpClient TestHost = new UdpClient(Global.HostEP);
TestHost.Client.Blocking = false;
enter image description here
Am trying to make a simple UDP application using C sharp,nothing sophisticated,connect,send some text,and receive it! but it keeps throwing this exception!
"An existing connection was forcibly closed by the remote host"!
The code :
byte[] data = new byte[1024];
IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050);
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
string welcome = "Hello, are you there?";
data = Encoding.ASCII.GetBytes(welcome);
server.SendTo(data, data.Length, SocketFlags.None, ipep);
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint tmpRemote = (EndPoint)sender;
data = new byte[1024];
int recv = server.ReceiveFrom(data, ref tmpRemote);
Console.WriteLine("Message received from {0}:", tmpRemote.ToString());
Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
Console.WriteLine("Stopping client");
server.Close();
thanks =)
You should tell the system that you are listening for UDP packets on port 9050 before you call Receive.
Add server.Bind(ipep); after Socket server = new Socket(...);
Have you tried checking that the IP address is valid and the port is not being used for something else?
Windows:
Start > Run > "cmd" > "ipconfig".
Try turning off your firewall software.
If you do not know the IP of the answering server, you better do:
recv = server.Receive(data);
Here is my suggetion to your code. You can use a do-while loop using a condition (in my example it is an infinite loop):
byte[] data = new byte[1024];
IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050);
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
string welcome = "Hello, are you there?";
data = Encoding.ASCII.GetBytes(welcome);
server.ReceiveTimeout = 10000; //1second timeout
int rslt = server.SendTo(data, data.Length, SocketFlags.None, ipep);
data = new byte[1024];
int recv = 0;
do
{
try
{
Console.WriteLine("Start time: " + DateTime.Now.ToString());
recv = server.Receive(data); //the code will be stoped hier untill the time out is passed
}
catch { }
} while (true); //carefoul! infinite loop!
Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
Console.WriteLine("Stopping client");
server.Close();