I'm doing a small project that consists on listening for a Ping and just answer back with some info.
I thought of using a Socket Raw for ICMP as listener in server-side and just send a ping from client-side, this works fine when I put the 127.0.0.1 address in the IPEndPoint, but this just let me go for local tests.
I want to ping from another computer in my ethernet connection and I must change that 127.0.0.1 address in the server-side, thought of using 192.168.0.112 as it's my local ip address, but it doesn't work. Any thoughts?
Here's my code:
server
Socket servidor = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 0);
servidor.Bind(endpoint);
servidor.IOControl(IOControlCode.ReceiveAll, new byte[] { 1, 0, 0, 0 }, new byte[] { 1, 0, 0, 0 });
Any help will be really appreciated! Thank you!
Related
I am using following code to connect to remote host:
IPHostEntry hostname = Dns.GetHostEntry("172.29.65.33");
IPAddress address = hostname.AddressList[0]; // IndexOutOfRangeException
...
My question is why AddressList is empty? Host is there, no SocketException is thrown...
Some details: customer has upgraded Windows XP to 8.1 and then all troubles begun.
I've read this and this topic, but unfortunately they are not useful to fix an issue, therefore asking it again.
Instead of resolving addresses via Dns
IPHostEntry hostname = Dns.GetHostEntry("172.29.65.33");
IPAddress address = hostname.AddressList[0];
...
IPEndPoint end = new IPEndPoint(address, port);
it can be simply parsed
IPEndPoint end = new IPEndPoint(IPAddress.Parse("172.29.65.33"), port);
This will eliminate all problems (socket exception, empty address list, etc.) related to using Dns.
How is it possible to get the dynamically assigned port of a IPEndPoint, when you create it with 0 as port:
var endpoint = new IPEndPoint(Dns.GetHostAddresses(localhost).FirstOrDefault(), 0);
If I look at the endpoint.Port, it is 0 (any), even tho the underlaying Socket must have an designated port already?
FYI:
Socket.RemoteEndPoint
Socket.LocalEndPoint
I created a small program to test UPnP Multicast (Visual C# 2010 Express, running on Windows 7 Professional 64 Bit). I can receive the UPnP NOTIFY Messages from UPnP Devices in my Network. But when i send the M-SEARCH Message, i get no Answers.
I have tested the same code on a iOS environment (Monotouch for iOS, running on a iPhone simulator on a Mac). There it runs fine and i get all the search responses from my UPnP devices. I can also see the M-SEARCH message from my windows program.
It looks like Windows (or a Firewall?) is hiding the search responses. Any idea?
Here is the code:
IPEndPoint LocalEndPoint = new IPEndPoint(IPAddress.Any, 1900);
IPEndPoint MulticastEndPoint = new IPEndPoint(IPAddress.Parse("239.255.255.250"), 1900);
Socket UdpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
UdpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
UdpSocket.Bind(LocalEndPoint);
UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(MulticastEndPoint.Address, IPAddress.Any));
UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 2);
UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, true);
Console.WriteLine("UDP-Socket setup done...\r\n");
string SearchString = "M-SEARCH * HTTP/1.1\r\nHOST:239.255.255.250:1900\r\nMAN:\"ssdp:discover\"\r\nST:ssdp:all\r\nMX:3\r\n\r\n";
UdpSocket.SendTo(Encoding.UTF8.GetBytes(SearchString), SocketFlags.None, MulticastEndPoint);
Console.WriteLine("M-Search sent...\r\n");
byte[] ReceiveBuffer = new byte[64000];
int ReceivedBytes = 0;
while (true)
{
if (UdpSocket.Available > 0)
{
ReceivedBytes = UdpSocket.Receive(ReceiveBuffer, SocketFlags.None);
if (ReceivedBytes > 0)
{
Console.WriteLine(Encoding.UTF8.GetString(ReceiveBuffer, 0, ReceivedBytes));
}
}
}
Yeah, I solved the problem! Small mistake, big impact:
My program is sending the M-SEARCH on port 1900 which is bound to the UPnP multicast group. Because i bound the LocalEndPoint to the same port, the UPnP devices answers with unicast to port 1900. On iOS it worked, because my program was the only service bound to this port. But on the PC, i found several services bound to port 1900 (found with "netstat -p UDP -a"). So the unicast messages from the UPnP devices was absorbed by one of the other services.
The solution: I bound the LocalEndPoint to a free port (e.g. 60000), and now it works fine!
IPEndPoint LocalEndPoint = new IPEndPoint(IPAddress.Any, 60000);
On create of local endpoint use port 0 (zero) to bind a free port not using a fixed port. Another point discovered. Binding IPAddress.Any or IPAddress.Loopback get responses from Microsoft (local?) system where as binding to one of the LAN address(es) get responses from the local net. Getting first IPV4 address can be done like this:
IPAddress localNetwork = Dns.GetHostAddresses(Environment.GetEnvironmentVariable("COMPUTERNAME")).Where(ia => (ia.AddressFamily == AddressFamily.InterNetwork)).First();
For posterity: setting all these options above is unnecessary for M-SEARCH and might even be counter-productive:
UdpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(MulticastEndPoint.Address, IPAddress.Any));
UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 2);
UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, true);
So don't do it.
ipEndReceive = new IPEndPoint(IPAddress.Parse("127.0.0.1"), receivePort);
receiveSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream
, ProtocolType.Tcp);
ErrorLog.WritetoErrorlog("Trying to Bind IP Address Stored in Variable : "
+ipEndReceive.Address.ToString()
+"\n Port No :"+ipEndReceive.Port.ToString(), logPath);
receiveSock.Bind(ipEndReceive);
ErrorLog.WritetoErrorlog("\nRemote IP Address : "
+ ((IPEndPoint)receiveSock.RemoteEndPoint).Address.ToString()
+ "\n Local IP:"
+ ((IPEndPoint)receiveSock.LocalEndPoint).Address.ToString()
, logPath);
Here receiveSock.RemoteEndPoint returns me an instance of EndPoint rather than IPEndPoint due to which i m not able to get the remote ip address from where request has been received.
Do we have any way to get it from this socket.
Socket RemoteEndpoint will be set after socket is connected.
That means that logging RemoteEndpoint after bind is not correct.
The RemoteEndPoint is set after a call to either Accept or Connect. If you try to access this property earlier, RemoteEndPoint will throw a SocketException. If you receive a SocketException, use the SocketException::ErrorCode property to obtain the specific error code. After you have obtained this code, refer to the Windows Sockets version 2 API error code documentation in the MSDN library for a detailed description of the error."
(from MSDN)
The client connects to the server using GenuineChannels (we are considering switching to DotNetRemoting). What I mean by find is obtain the IP and port number of a server to connect to.
It seems like a brute-force approach would be try every IP on the network try the active ports (not even sure if that's possible) but there must be a better way.
Consider broadcasting a specific UDP packet. When the server or servers see the broadcasted UDP packet they send a reply. The client can collect the replies from all the servers and start connecting to them or based on an election algorithm.
See example for client (untested code):
using System.Net;
using System.Net.Sockets;
[STAThread]
static void Main(string[] args)
{
Socket socket = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp);
socket.Bind(new IPEndPoint(IPAddress.Any, 8002));
socket.Connect(new IPEndPoint(IPAddress.Broadcast, 8001));
socket.Send(System.Text.ASCIIEncoding.ASCII.GetBytes("hello"));
int availableBytes = socket.Available;
if (availableBytes > 0)
{
byte[] buffer = new byte[availableBytes];
socket.Receive(buffer, 0, availableBytes, SocketFlags.None);
// buffer has the information on how to connect to the server
}
}
I'd say the best way is to use Bonjour/Zeroconf/mDNS for C#; a lot of thought went into making it play nice with the network; IE it pings less frequently over time if possible, etc. There's Mono.Zeroconf, and I read there's an older .NET project in the Apple SDK but I haven't found it.
So the easiest would be to install Bonjour for Windows, then get the Windows Binaries for Mono.Zeroconf try the example MZClient.exe drop the Mono.Zeroconf.dll and/or Mono.Zeroconf.Providers.Bonjour.dll into your project references and go.
Something like this:
var service = new Mono.Zeroconf.RegisterService {
Name = "Use Me for Stuff",
RegType = "_daap._tcp",
ReplyDomain = "local.",
Port = 0024200,
TxtRecord = new Mono.Zeroconf.TxtRecord {
{"I have no idea what's going on", "true"}}
};
service.Register();
var browser = new Mono.Zeroconf.ServiceBrowser();
browser.ServiceAdded +=
delegate(object o, Mono.Zeroconf.ServiceBrowseEventArgs args) {
Console.WriteLine("Found Service: {0}", args.Service.Name);
args.Service.Resolved +=
delegate(object o, Mono.Zeroconf.ServiceBrowseEventArgs args) {
var s = args.Service;
Console.WriteLine(
"Resolved Service: {0} - {1}:{2} ({3} TXT record entries)",
s.FullName, s.HostEntry.AddressList[0], s.Port, s.TxtRecord.Count);
};
args.Service.Resolve();
};
browser.Browse("_daap._tcp", "local");
Just wanted to point out an alternative Zeroconf NuGet package: Zeroconf. It does not have any native dependencies, so you don't need to install Bonjour for Windows or anything else.
It has support for .NET 4.5, WP8 and Win8.
WS-Discovery is a protocol intended for this purpose. It has a few different variations, different flavors of broadcasting and proxies. http://en.wikipedia.org/wiki/WS-Discovery
.NET WCF4 implements this.
Have the server listen for broadcast on a specific port on the network (must use UDP), When client starts have it broadcast some "ping" request on that port. when the server sees a "ping" it send back a message with the TCP address and port required for the client to connect to it.