TcpClient(IPEndPoint localEP), choosing correct localEp? - c#

I'm driving myself crazy.
Microsoft provides an awesome way of binding a local network adaptor and port for a new TCPClient by using the constructor:
TcpClient newClient = new TcpClient(IPEndPoint localEP);
Given a general remoteEndPoint, either IPv4 or IPv6, and assuming MANY possible localEPs, there does not seem to be a sensible way of determining which localEP to bind to before then calling:
TcpClient.Connect(IPEndPoint remoteEP)
.net does provide a parameterless TcpClient constructor, which will automatically determine which localEP is best when calling .Connect but unfortunately that does not support IPv6 targets.
My first thought was to access the IP routing table and working out myself which adaptor to use but it seems .net does not provide that functionality either.
I have found a solution which involves a P.Invoke to GetBestInterface() but unfortunately I need to be able to deploy in Mono so really need a managed solution.
My question/problem is: Given a known remoteEP, and a list of all known localEPs how do I correctly choose the correct localEP when instantiating the tcpClient so that the connect method is successful.

If what you're asking is what to use for localEP, you could use new IPEndPoint(IPAddress.Any, myPort) This will bind to any available IP addresses on the local computer and use port myPort. That way something can connect to the computer with whatever IP it likes. If you have multiple IPs (e.g. NICs) it can connect, if i has IPv4 and IPv6, it can connect to either.
e.g. :
var client = new TcpClient(new IPEndPoint(IPAddress.Any, myPort));
But, you can normally just use new TcpClient();

Related

How to run client and server UDP listeners on the same machine

Both client and server send and receive on a given port. In production they are on separate machines and there is no problem. In development it would be a great deal more convenient to run them on the same machine and avoid the need for deployment and setting up and tearing down a remote debug session.
I tried this
var uc = new UdpClient();
var ep = new IPEndPoint(address, port);
uc.ExclusiveAddressUse = false;
uc.Client.Bind(ep);
and it doesn't barf but I still can't bind multiple listeners to the same endpoint. After the fact I discovered that ExclusiveAddressUse defaults to false anyhow so this approach produces nothing but extra code.
Is this possible and if so how?
You obviously cant use the same port on the same machine, just use an #if directive for debug and change your ports accordingly
The following might help
Client
#if DEBUG
uc client = new UdpClient(34534);
#else
uc client = new UdpClient();
#endif
UdpClient Constructor (Int32)
Initializes a new instance of the UdpClient class and binds it to the
local port number provided.
Remarks
This constructor creates an underlying Socket and binds it to the port
number from which you intend to communicate. Use this constructor if
you are only interested in setting the local port number. The
underlying service provider will assign the local IP address. If you
pass 0 to the constructor, the underlying service provider will assign
a port number. If this constructor is used, the UdpClient instance is
set with an address family of IPv4 that cannot be changed or
overwritten by a connect method call with an IPv6 target.
Disclaimer, totally untested, just read the documentation, possibly wrong :)

Only one use of each socket address (proto/ip/port)

Good day all
Info:
Topic: Multicast
First off, I have found the solution but I do not understand why this is the solution.
**Scope : ** (removing any cluttering/unnecessary code)
new_socket()
{
//SND_LOCAL_IP = 10.0.0.30 - local network adapter's IP
//SND_MCAST_PORT = 80 port used to broadcast Multicast Packets
//_SND_LOCAL_EP = new IPEndPoint(SND_LOCAL_IP, SND_MCAST_PORT); <problem>
_SND_LOCAL_EP = new IPEndPoint(SND_LOCAL_IP, 0); <fixed>
}
init_socket()
{
_SND_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
_SND_Socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(_SND_MCAST_IP, _SND_LOCAL_IP));
_SND_Socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.ReuseAddress, true);
_SND_Socket.ExclusiveAddressUse = false;
_SND_Socket.Bind(_SND_LOCAL_EP); <<< ====== PROBLEM LINE=====
}
The problem:
My listener runs on a Thread seperately, on a form_load event, thus it initializes in the same way as my SND_Socket does, however changing the SND_Socket.Bind() port to 0 allows me to recieve these Multicast packets.
As by the def MSDN, adding the ExclusiveAddress should not alleviate this problem (since the recieve and send sockets are initialized in the same way).
true if the Socket allows only one socket to bind to a specific port; otherwise, false. The default is true for Windows Server 2003 and Windows XP Service Pack 2, and false for all other versions.
and further on, in Remarks this is confirmed:
If ExclusiveAddressUse is false, multiple sockets can use the Bind method to bind to a specific port; however only one of the sockets can perform operations on the network traffic sent to the port. If more than one socket attempts to use the Bind(EndPoint) method to bind to a particular port, then the one with the more specific IP address will handle the network traffic sent to that port.
If ExclusiveAddressUse is true, the first use of the Bind method to attempt to bind to a particular port, regardless of Internet Protocol (IP) address, will succeed; all subsequent uses of the Bind method to attempt to bind to that port will fail until the original bound socket is destroyed.
This property must be set before Bind is called; otherwise an InvalidOperationException will be thrown.
Why does the
Socket.ExclusiveAddress = false
not allow the SND_Socket to listen on this IP and port as "Listener_Socket", furthermore why does setting port to 0 in the RCV_Socket.Bind() solve this problem?
Without a good Minimal, Complete, and Verifiable Example it's impossible to know for sure what problem you're even having specifically, never mind know for sure what the cause would be. Lacking that, some observations/comments related to the question as stated:
The ExclusiveAddressUse property affects not the socket on which it's set, but any other socket bound after that socket. It prevents any other socket from using the same port number, i.e. which it would otherwise be able to do through the ReuseAddress socket option.
The ReuseAddress socket option does affect the socket on which it's set. It's what allows a socket to bind to the same port that some other socket on the same adapter had already been bound.
One would typically not use both of those options at the same time. Either you want the sockets to cooperate, where one allows the other to reuse the same port number, or you want to prohibit any other socket from using the same port number.
Binding to port 0 can in some cases alleviate issues that might otherwise occur when misusing the address-exclusivity options. With the incomplete question, I cannot infer what specific problem you are having. But binding to port 0 causes the socket to select a unique port number, which will of course avoid any problems with port number conflicts.
Other than that, the biggest issue I see in your code is that you are attempting to join the multicast group before you call Bind(). You should be doing it the other way around, i.e. bind the socket, and then join the multicast group.
Most likely, you should not be using ReuseAddress at all. Your sockets should have unique port numbers. You may use ExclusiveAddressUse, as a preventative measure to ensure you get an exception if some code does try to bind a socket to a port that's already in use.
I recommend that you start by closely following the example found on MSDN on the documentation page for the MulticastOption Class. Once you have a working example using that code, then you can adjust the code to suit your specific needs.

TCP Client problems

I have few questions (and problems) about the tcp client class.
1. What IP should I give to it constructor, mine or the remote host that I want to connect to? because in MSDN I see that the constructor takes a local ip endpoint and I can't understand it.
2. What may be the reason for such statement:
TcpClient client = new TcpClient(ip.Text, port: portNum);
to stop the code from running without throwing an exception?
1. The IP you should give to the constructor
You should give the IP you want to connect, look about the IPAddress class.
2. The reason of the statement
Why did you type port: portNum ?
Just write like what is writed in the official documentation :
//Creates a TCPClient using host name and port.
TcpClient tcpClientB = new TcpClient ("www.contoso.com", 11000);
System.Net.Sockets.TcpClient has four constructors. The two constructors that seem to be the source of confusion are:
TcpClient(IPEndPoint) - binds it to the specified local endpoint.
TcpClient(String, Int32) - connects to the specified port on the specified host.
Constructor #1 is useful if your computer has more than one NIC (e.g. Ethernet and WiFi) and you want to pick which one to use. If you construct your TcpClient instance this way, then you would explicitly call TcpClient.Connect to connect the remote host and port number.
Constructor #2 creates the TcpClient instance (picking a local endpoint automatically) and immediately connects using the supplied remote host and port.

Discovery in c#

I've to implement some discovery for an internal solution.
We have two kind of software:
Server: They manage a lot of hardware devices and can give access to some data (.Net remoting)
Client: They can display data of one or several Server(graphs, stats, ...)
Currently we are setting the IP by hand on the client.
We would like to implement a discovery.
We have the following requirement:
It has to be usable in c#
When a server is up, it must be displayed as available very fastly
Same when it shut down
If the server doesn't stops in a clean way, we can have a way to detect it(no need to be very fast, can be done every 10-15min).
It can give me some information(Server version, port to use, ...)
We have client computer with multiple network cards, we must discover server on each cards
Do you have a protocol, a library, ... to advice?
We tried UPnP, but seems there is no good Server+client implementation in c# that meet our requirement
Use UDP broadcasts from the discovering app (client):
int broadcastPort = //something
byte[] msg = //something
//Cycle this for all IP adresses
IPAddress broadcastIp = //Broadcast address for this net
IPEndPoint destinationEndpoint = new IPEndPoint(broadcastIp, broadcastPort);
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
sock.SendTo(msg, broadcastEndpoint);
And have the discovered app (Server) answer, to receive the answer use UdpClient.Receive(), which gives you the IP of the answering station.

not connecting to server problem in C#

I am running a client/server application. I use a textbox to let the user type in the IP address and port. I try to connect to the server, using 127.0.0.1 and there is no problem. After that I tried using 192.168.2.102 (NAT ip address of this computer), and it fails. Any idea why?
the code I am using is: (this the the part that connects)
connect(string IPaddress, int port)
{
TcpCLient connection = new TcpClient();
connection.Connect(IPaddress, port);
}
I checked with debug, it DOES use the right IPaddress and port.
Firewall should allow it to connect. It's weird.
EDIT:
I think I know the problem. At the server side, I use
_listener = new TcpListener(IPAddress.Loopback, 8001);
And I think that's the reason why it only accepts connections from 127.0.0.1. But then, what should I use instead? I just want any connection from any IP with this port.
If you are specifying IPAddress.Loopback, then only connections to 127.0.0.1 will work. Replace it with IPAddress.Any to tell your server to listen on all interfaces.
First of all, the only circumstance I've ever seen return Connection was not possible because the destination computer actively rejected it is when there is actually nothing listening for connections at the specified address and port... or there is a firewall.
You may want to verify with a tracert that 192.168.2.102 actually points where you think it does. Another option is to use telnet from the command line to connect to the address and port if you really suspect there is a problem in your code (although I cannot see that apply here).
Addendum:
Is there any other application that can successfully make a connection to that specific IP address on that same machine?

Categories