All I need to do is sending out a broadcast message with an ASCII encoded command and wait for an answer.
I've found numerous tutorials on how to do this and nearly figured everything out. I studied the MSDN articles about sockets and it's SendTo method but whatever I do or try it raises this exception at my SendTo call:
System.Net.Sockets.SocketException: 'The attempted operation is not supported for the type of object referenced'
The provided error code is 10045. Not very detailed as so often in low level APIs.
I assume it should be correct. I bind to my Ethernet adapter (the one hooked up to the intranet where my device I'm trying to contact resides) on any available port and broadcast to that port I am looking for.
That's my code so far:
byte[] encoded = Encoding.ASCII.GetBytes(cast);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1);
socket.Bind(new IPEndPoint(IPAddress.Parse("192.168.10.87"), 0));
IPEndPoint broadcastPartner = new IPEndPoint(IPAddress.Broadcast, 32001);
int sent = socket.SendTo(encoded, SocketFlags.Broadcast, broadcastPartner);
Console.WriteLine($"Sent {sent} bytes.");
SpinWait wait = new SpinWait();
while (true)
{
byte[] buffer = new byte[2048];
int read = 0;
try
{
read = socket.Receive(buffer, SocketFlags.Broadcast);
}
catch (Exception)
{
wait.SpinOnce();
continue;
}
if (read == 0) continue;
Console.WriteLine("Received message: " + Encoding.ASCII.GetString(buffer));
}
Related
I want to send 5 messages from port 7021 to listener of port 7022.
This means that single client send multiple messages to listener.
Following is the implementation:
string message = "787814014E612096";
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("192.168.0.126"), 7021);
var endpoint = new IPEndPoint(IPAddress.Parse("192.168.0.126"), 7022);
// Create a TCP/IP socket.
Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sender.Bind(endpoint);
sender.Connect(remoteEP);
Console.WriteLine("Socket connected to {0}", sender.RemoteEndPoint.ToString());
int index = 1;
while (index < 6)
{
Console.WriteLine("Send packet: " + index);
byte[] msg = Encoding.ASCII.GetBytes(message);
int bytesSent = sender.Send(msg);
Thread.Sleep(2000);
index = index + 1;
}
// Release the socket.
sender.Shutdown(SocketShutdown.Both);
sender.Close();
Any help in this regard will be appreciated.
Some key points:
Use TcpClient and TcpListener instead of sockets.
Use the Task Async Pattern instead of Async callbacks.
Use the OS to allocate a source port instead of allocating one manually.
Use Task.Delay() instead of Thread.Sleep();
The following line, asks the operating system to send the data.
int bytesSent = sender.Send(msg);
However, you have no way of guaranteeing that the OS will send the data immediately, it can, and sometimes will hang on to that data and send it later.
You also need to be checking bytesSent to find out how many bytes were placed in the outbound queue.
Using TcpClient and the NetworkStream that comes with TcpClient will alleviate a lot of the Socket edge cases that you will encounter.
I am aware that there a plenty of questions on UDP broadcast for detecting network devices but none of the answers really work for me. I'm guessing that I'm missing something and would be grateful for any help.
I have designed a system which sits on a network and runs a UDP server. Upon receiving a message on some port (AP) it will send a reply back to the sending IP/port.
On the C# side I use the following code:
UdpClient Client = new UdpClient();
var RequestData = Encoding.ASCII.GetBytes("Discover");
var ServerEp = new IPEndPoint(IPAddress.Any, 0);
byte[] ServerResponseData = { 0 };
Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000);
Client.EnableBroadcast = true;
Client.Send(RequestData, RequestData.Length, new IPEndPoint(IPAddress.Broadcast, AnnouncePort));
ServerResponseData = LanguageUtils.IgnoreErrors(() => Client.Receive(ref ServerEp));
if (ServerResponseData != null)
{
var ServerResponse = Encoding.ASCII.GetString(ServerResponseData);
deviceList.Add(ServerEp.Address.ToString());
QueryFoundDevices(deviceList);
AvailableDevicesList.Nodes[0].Expand();
}
My issue is that I can only ever detect one of my devices at a time. Ideally, I would like to be able to receive messages from an unlimited number of devices.
I have also tried using async methods, in which case I just receive my own message and don't see any devices. Code example of that:
static void OnUdpData(IAsyncResult result)
{
// this is what had been passed into BeginReceive as the second parameter:
UdpClient socket = result.AsyncState as UdpClient;
// points towards whoever had sent the message:
IPEndPoint source = new IPEndPoint(0, 0);
// get the actual message and fill out the source:
byte[] message = socket.EndReceive(result, ref source);
// do what you'd like with `message` here:
Console.WriteLine("Got " + message.Length + " bytes from " + source);
// schedule the next receive operation once reading is done:
socket.BeginReceive(new AsyncCallback(OnUdpData), socket);
}
Can anyone please advise how I can do this?
Update:
Based on comments - these are Ethernet based devices and I have verified that both devices are replying using Wireshark.
I don't know where is is correct to do this but I have now worked out a way of doing this based upon Lex Li's comment. I thought I would share this just in case anyone else is having a similar issue.
UdpClient Client = new UdpClient();
var RequestData = Encoding.ASCII.GetBytes("Discover");
var ServerEp = new IPEndPoint(IPAddress.Any, 0);
byte[] ServerResponseData = { 0 };
Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000);
Client.EnableBroadcast = true;
Client.Send(RequestData, RequestData.Length, new IPEndPoint(IPAddress.Broadcast, AnnouncePort));
ServerResponseData = LanguageUtils.IgnoreErrors(() => Client.Receive(ref ServerEp));
string ServerResponse;
while (ServerResponseData != null)
{
ServerResponse = Encoding.ASCII.GetString(ServerResponseData);
deviceList.Add(ServerEp.Address.ToString());
QueryFoundDevices(deviceList);
AvailableDevicesList.Nodes[0].Expand();
ServerResponseData = LanguageUtils.IgnoreErrors(() =>Client.Receive(ref ServerEp))
}
Lex Li pointed out that the first code section I posted in my answer would only receive the first reply. I tried to read the next response and it worked. I am now using the above, which likely needs further optimisation but is working well so far.
Thanks for the help folks!
i have tried to make TCP/IP connection for a server/client application with asynchronous socket communication and it was successful. However, i am not able to display all the message received by client. i have run time error, may i know where is the problem.
private void onreceive(IAsyncResult ar)
{
Socket clientsocket = (Socket)ar.AsyncState;
int byteread = clientsocket.EndReceive(ar);
data msgreceived = new data(byteData,byteread);
data msgtosend = new data();
byte[] message;
ClientInfo clientinfo = new ClientInfo();
clientinfo.socket = clientsocket;
IPEndPoint remote = clientsocket.RemoteEndPoint as IPEndPoint;
remoteip = remote.Address;
clientinfo.IMEI = msgreceived.IMEI;
clientlist.Add(clientinfo);
msgtosend.strMessage = "client with ip address " + remoteip + " with this IMEI " + clientinfo.IMEI;
txtLog.Text += msgreceived.strMessage + "\r\n";
if (clientinfo.socket.Connected == true)
{
clientsocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(onreceive), clientsocket);
}}
in data class:
public data(byte[] Data, int msglen)
{
//int imeilen = BitConverter.ToInt32(Data, 0);
//int msglen = BitConverter.ToInt32(Data, 4);
//if (imeilen > 0)
// this.IMEI = Encoding.ASCII.GetString(Data, 8, imeilen);
//else this.IMEI = "unknown";
if (msglen > 0)
this.strMessage = Encoding.ASCII.GetString(Data,0, msglen);
else
this.strMessage = "no message";
}
You are somehow magically expecting to know when you have received a "message" despite not even having decided what a message is or writing any code to determine whether one has been received.
There is an old saying in the TCP programming community -- nobody is allowed to write any code that uses TCP until they can 100% explain what every word in this true statement means:
"TCP is a reliable, byte-stream protocol that does not preserve application message boundaries."
You have to code to implement a "message". TCP is a byte-stream protocol. If you want to send and receive messages, you'll need to create a protocol that does that.
Start by defining what a message is, how one is delimited, and so on. Then write code to send and receive messages according to your definition. When your onReceive function is called, that just means the TCP/IP stack received some bytes -- you need to decide whether that's a message or not by following the rules for a the messaging protocol.
Im new to Sockets and C# in general and am having a difficult time implementing a simple upd listener function. I've spent alot of time searching the web tying unsuccessfully to intergate any of the numerious examples online. So any suggestions, links, examples would be greatly appreciated!
At this point, I have a third party application broadcasting over port 6600 a general UPD message containing information about the location of the application server (ServerName, IP Address, etc.). I'd like to design my listener client application to capture the UPD broadcast and generate a collection of the available servers which can be used to future processing.
The problem I'm having is that when I attempt to create the listener using listener.Listen(0) if fails and generates a general type error. If I attempt to us the UdpClient class my application hangs and never returns any data. The Code for both examples is listed below:
namespace UDPListener
{
class Program
{
static void Main(string[] args)
{
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
listener.Bind(new IPEndPoint(IPAddress.Any, 6600));
listener.Listen(6);
Socket socket = listener.Accept();
Stream netStream = new NetworkStream(socket);
StreamReader reader = new StreamReader(netStream);
string result = reader.ReadToEnd();
Console.WriteLine(result);
socket.Close();
listener.Close();
}
}
}
And the UdpClient:
private void IdentifyServer()
{
//Creates a UdpClient for reading incoming data.
UdpClient receivingUdpClient = new UdpClient(6600);
//Creates an IPEndPoint to record the IP Address and port number of the sender.
// The IPEndPoint will allow you to read datagrams sent from any source.
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
try
{
// Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = receivingUdpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);
Output.Text = ("This is the message you received " +
returnData.ToString());
Output.Text = ("This message was sent from " +
RemoteIpEndPoint.Address.ToString() +
" on their port number " +
RemoteIpEndPoint.Port.ToString());
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
dtb was absolutely write! After much research and some help from a friend I realized that what I was actually looking for was a solution for Multicasting. I'll include the links below.
#dtb, thanks for helping point me in the right direction!
http://www.codeproject.com/Articles/1705/IP-Multicasting-in-C
http://codeidol.com/csharp/csharp-network/IP-Multicasting/Csharp-IP-Multicast-Support/
I created an application with server and client tool using sockets etc. When using my code on my computer works. Now I installed the Himachi software and I need to use this software in my application so that when a user connects with me, the application created could be used in this network. Note that this is my first time using sockets. The problem is that they are not connecting to each other and also it gives me this error on changing the ip and port: The requested address is not valid in its context
The send Tool
public Send(string Group, string port, string ttl, string rep, string data)
{
IPAddress ip;
try
{
Console.WriteLine("Send on Group: {0} Port: {1} TTL: {2}", Group,port,ttl);
ip = IPAddress.Parse(Group);
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(ip));
s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, int.Parse(ttl));
IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(Group),int.Parse(port));
Console.WriteLine("Connecting...");
s.Connect(ipep);
byte[] byData = System.Text.Encoding.ASCII.GetBytes(data);
s.Send(byData, SocketFlags.None);
Console.WriteLine("Closing Connection...");
s.Close();
}
catch(System.Exception e) { Console.Error.WriteLine(e.Message); }
}
The Receive tool
public string RecvData(string Group, string port)
{
string str = "";
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, int.Parse(port));
s.Bind(ipep);
IPAddress ip = IPAddress.Parse(Group);
s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(ip,IPAddress.Any));
// Getting the data
byte[] buffer = new byte[1024];
int iRx = s.Receive(buffer);
str = System.Text.Encoding.ASCII.GetString(buffer, 0, buffer.Length);
// Closing a Socket
s.Close();
return str;
}
Thanks
So your problem is that you are trying to use a VPN (hamachi) to connect two apps the server and the client so that the client can receive messages from the server right? I think that the error given "The requested address is not valid in its context" is because you are using a VPN but I don't know how this can be solved sorry. What I think is that maybe you might also need the network id and password but again I'm not sure. Please keep us informed because this is a very interesting question.