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.
Related
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;
}
}
I am using sockets for TCP-IP connection and I would like to establish simple system send-receive from the client side.
Socket sck;
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEndpt = new IPEndPoint(IPAddress.Parse("123.123.123.1"), 12345);
try
{
sck.Connect(localEndpt);
}
catch
{
Console.Write("Unable to Connect");
}
while (true)
{
Console.WriteLine("Enter Text");
string sendtext = Console.ReadLine();
byte[] Data = Encoding.ASCII.GetBytes(sendtext);
sck.Send(Data);
Console.WriteLine("Data Sent!");
byte[] bytesReceived = new byte[sck.ReceiveBufferSize];
int bytes = 0;
String strReceived = "";
int dataAvailable = 0;
while (dataAvailable == 0 || dataAvailable != sck.Available)
{
dataAvailable = sck.Available;
Thread.Sleep(100); // if no new data after 100ms assume transmission finished
}
if (sck.Available > 0)
{
bytes = sck.Receive(bytesReceived, bytesReceived.Length, 0);
strReceived+=Encoding.ASCII.GetString(bytesReceived, 0, bytes);
}
Console.WriteLine("Received from server: " + strReceived);
}
Console.Read();
The problem is that first requests goes throught but the second does not, because socket is not available anymore (socket "Availabe" attribute value is 0). What am I doing wrong? What would be the easiest way to establish multiple send-recieve requests (in order)?
This code works fine for me
private List<Socket> _clients = new List<Socket>();
private Thread _dataReceiveThread;
private bool _isConnected;
private void DataReceive()
{
while (_isConnected)
{
List<Socket> clients = new List<Socket>(_clients);
foreach (Socket client in clients)
{
try
{
if (!client.Connected) continue;
string txt = "";
while (client.Available > 0)
{
byte[] bytes = new byte[client.ReceiveBufferSize];
int byteRec = client.Receive(bytes);
if (byteRec > 0)
txt += Encoding.UTF8.GetString(bytes, 0, byteRec);
}
if (!string.IsNullOrEmpty(txt))
/* TODO: access the text received with "txt" */
}
catch (Exception e)
{
Exception_Handler(e);
}
}
}
}
Just run this code to get started
_isConnected = true;
_dataReceiveThread = new Thread(DataReceive);
_dataReceiveThread.Start();
Update list box in Cross thread:
This code can be placed in the comment section.
myListBox1.Invoke((Action)(() => { myListBox1.Items.Add(txt) }));
Socket. Available does NOT indicate whether the socket is available, but incoming data is available for reading:
https://msdn.microsoft.com/en-us/library/ee425135.aspx
Your program quits because it checks for a reply (incoming data) immediately after sending a message out. Use a Thread.Sleep before checking for data.
Maybe the message has not even been sent, because Socket.Send just places it in the network interface card's output buffer. When the socket finally sends the message, it will upare the connection state. If it got no reply (on a TCP connection), it will tell you that it is disconnected when you query the state. On UDP it will tell you nothing, because UDP is connectionless.
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;
}
I have c# code which is connecting to localhost ip address 127.0.0.1 and port no. 5939. Connection is happening perfectly but it is not receiving any data. I want it to receive data and save it to text file on my local machine.
Does it not receiving data because it is on the localhost and on the same machine or there is error in my code ..
Here is my code..
byte[] data = new byte[1024];
string input, stringData;
String ip = "127.0.0.1";
Int32 port = 5939;
string path = "D://ipdata.text";
if (File.Exists("D://ipsettings.txt"))
{
File.Delete("D://ipsettings.txt");
}
IPAddress ipad = IPAddress.Parse(ip);
IPEndPoint ipend = new IPEndPoint(ipad, port);
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
sock.Connect(ipend);
}
catch (Exception ex)
{
throw ex;
}
try
{
int recv = sock.Receive(data);
stringData = Encoding.ASCII.GetString(data, 0, recv);
while (true)
{
input = "Client here";
sock.Send(Encoding.ASCII.GetBytes(input));
data = new byte[1024];
recv = sock.Receive(data);
stringData = Encoding.ASCII.GetString(data, 0, recv);
string df = "";
try
{
System.IO.FileInfo fi = new System.IO.FileInfo(path);
My program is not executing after this line..
int recv = sock.Receive(data);
Please help me to get out of this situation.
Thanks in advance.
You need to read the data until unless the Receive function gives you.
use while loop to determine whether data is available or not.
int recv=0;
byte[] data = new byte[1024];
StringBuilder sb= new StringBuilder();
while ((recv=sock.Receive(data)) > 0)
{
sb.Append(Encoding.ASCII.GetString(data, 0, recv));
}
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