Why must I use default TcpClient to connect to server? - c#

Using the following code, my client fails to connect my server:
private static TcpClient client = new TcpClient(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 0));
private static IPEndPoint destinationEp = new IPEndPoint(IPAddress.Parse("192.168.0.100"), 1234);
//...
client.Connect(destinationEp);
Using TcpClient client = new TcpClient() instead will work.
In the original case, my understanding is that I am setting the local IP to the local machine, and using any available port as the local port to facilitate communication. My suspicion is that the server is trying to connect to the client using the IP "127.0.0.1", which wouldn't work, but I don't know this for sure.
Why do I have to use new TcpClient() instead of new TcpClient(myEndpoint) to successfully establish a server connection?

See the docs:
Initializes a new instance of the TcpClient class and binds it to the specified local endpoint.
Emphasis mine. You use that constructor only if you want to control the local part of the socket. See also the remainder of the docs:
You do not need to specify a local IP address and port number before connecting and communicating. If you create a TcpClient using any other constructor, the underlying service provider will assign the most appropriate local IP address and port number.
So your suspicion is correct. You're basically telling the network stack that you want your end of the socket to be bound to 127.0.0.1:0, which won't work for outbound connections.

Related

Local Inter-process Communication via TCP Sockets in C#

I get an exception when doing this in one thread:
var listener = new TcpListener(new IPEndPoint("127.0.0.1", 3536));
listener.Start();
System.Net.Sockets.SocketException (0x80004005): Address already in use
and this in another thread:
var client = new TcpClient(new IPEndPoint("127.0.0.1", 3536));
I know that I can't create two sockets on the same port, but I want one thing and the other receiving.
What I want to achieve is inter-process communication between a LOCAL C# and Python program. I've opted for sockets cause pipes work differently on Windows and Unix Systems and I wanted the possibility to outsource one program to another machine.
Edit: The TCP listener runs flawlessly when I remove
var client = new TcpClient(new IPEndPoint("127.0.0.1", 3536));
Edit2: I've had a
Thread.Sleep
on my main Thread. If I replace it with
while (!client.Connected) client.Connect(ipEndPoint)
Console.WriteLine(client.Connected) // this reaches
I don't currently know about data-transfer yet
You are using the wrong constructor.
TcpClient(IPEndPoint)
Initializes a new instance of the TcpClient class and binds it to the specified local endpoint.
What you probably want is this:
TcpClient(String, Int32)
Initializes a new instance of the TcpClient class and connects to the specified port on the specified host.
See TcpClient constructors
Some knowledge: A client needs a free port too. Normally it will binds to a random free port. For a local connection are two sockets required - one for the client and one for the server.

SocketException: The requested address is not valid in the context

I am able to communicate with socketTest with the same ip address, but within UNITY I get an error message
SocketException: The requested address is not valid in the context.
I tried
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(new IPEndPoint(IPAddress.Parse(sHostIpAddress), nPort));
sHostIpAddress is not 127.0.0.1
How to can i fix it?
This is not really specific to Unity but rather c# in general.
Socket.Bind is for binding the socket to a specific local endpoint! Such as for example you want to limit the socket to a specific local network adapter / address (by default it will use any/all) or a specific local port (by default it will pick any free local port)
Use the Bind method if you need to use a specific local endpoint. You must call Bind before you can call the Listen method. You do not need to call Bind before using the Connect method unless you need to use a specific local endpoint.
Usually you use Bind mostly for the server side for listening and waiting for incoming connections or for connectionless protocols like UDP.
You most probably simply want to rather use Socket.Connect for establishing a connection to a remote server.
When using Connect without Bind then it will simply pick the network adapter / address it finds to be the best fit for reaching the given host address and picks the next free local port.
However, in general I would recommend to rather use TcpClient instead of composing and configuring the Socket "manually" (except the use case requires it).
var tcpClient = new TcpClient(sHostIpAddress, nPort);
This constructor will automatically start a connection attempt. TcpClient is an IDisposable and cleans up the underlying socket, stream etc when it is disposed. It also is (in my eyes) way easier to configure and to sent and receive data with it.

Multiple TcpClients with same local port in C#

I'm working on a peer-to-peer file sharing application that can be used to transfer files without having a central server.
It works like a charm when it comes to one-to-one file transfer, however I originally planned it in a way, that the sender can send files to multiple clients.
The app uses TCP Hole Punching so port forwarding is not necessary. The problem is, that in order to make TCP hole punch work, I need to specify a local port for each TCPClient. Thus, I need to bind the sockets.
TCPClient client = new TCPClient(port);
The problem is, that when it comes to the creation of the a new client (after establishing a connection), I'll get the error which states I am unable to bind a new socket.
As far as I'm concerned, a socket is identified as a Local Port with Local IP AND Remote Port with Remote IP AND Protocol. Thus, if two sockets differ in one of these 4, they can be handled as separate connections.
Yet, I still get exception.
How can I do TCP Hole Punching with multiple clients? According to this wikipedia page, it should work, if the sender does not bind the sockets.
Here is the code for my Connect() method in my custom NetClient class. (It contains a TcpClient and represents a connection with a remote endpoint.)
private async Task<bool> Connect(string _ip)
{
IPEndPoint _endPoint = new IPEndPoint(IPAddress.Any, port);
tcpClient = new TcpClient(_endPoint);
int tick = timeOut;
while (tick >= 0)
{
try { await tcpClient?.ConnectAsync(_ip, port); }
catch { }
if (tcpClient.Connected) return true;
tick--;
await Task.Delay(1000);
}
return false;
}
Still, no luck. Can someone help please?
Okay, I've found a solution! For those who might stuck with the same problem, apparently there is an option to tell the TCP socket that the local endpoint can be reused.
Depending on the OS and the TCP implementation, you can add the option SO_REUSEADDRESS and SO_REUSEPORT for the socket. This will make the socket ignore endpoint duplication. (As far as I'm concerned it only works on the local endpoint.)
Head over this website for further information on the topic, it is a very good read.
Now for that, you will need to set these properties BEFORE binding the socket. So you will need to call socket.Bind() separately from the TcpClient constructor.
Use TcpClient.Client to access the socket of the tcpClient.
Proper way of creating a TcpClient with reusable local endpoint:
TcpClient client = new TcpClient();
client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseUnicastPort, true);
client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
client.Client.Bind(new IPEndPoint(IPAddress.Any, port));
After these steps, you should not experience any problem with socket binding. Hope that helped!

Connect TcpClient to a remote Tcp server, binding to a specific local port

I built tcp client/server application for my organisation. The server opens and listens to a specific port, and each client establishes Tcp Connection to the server port. Nothing special. The application works beautifully. But today, one client wanted the Tcp client app to work over WiFi network with firewall. The WiFi firewall is configured to block all ports by default. If I want my application to work, I have to give their network administrator a list of ports to open for my application. The server listening port is configurable so it is easy. Once I configure the port, I can give them is this specific port for the server. However the client app is unable to connect to the server because each time a TcpClient establishes a connection, it creates a random local Tcp port that will be blocked by their firewall.
Their network admin will not open all ports for the machine because they said it created security risks for their organisation. Therefore, I am looking for a way to force the client to open a specific local port when it establishes a Tcp connection. I've both looked into MSDN docs and been Googling but I haven't found an adequate answer. Would you be able to suggest a workaround or a third party library that can do that? Thank heaps.
I'm not aware of any way to have this level of control with TcpClient. However, if you manually create the Socket object, you can bind to a local port of your choosing:
var sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Specify the local port to use
var endpoint = new IPEndPoint(IPAddress.Any, 9999);
sock.Bind(endpoint);
// And connect to the remote end point
sock.Connect("example.com", 80);
Of course, by doing this you limit yourself to one connection on the machine.
how about use bind() like this(if you are using c++)
struct sockaddr_in cli;
memset(&cli, 0x00, sizeof(cli));
cli.sin_family = AF_INET;
cli.sin_port = htons(YOUR PORT);
cli.sin_addr.s_addr = inet_addr(YOUR IP ADDRESS);
int on = 1;
if (setsockopt(hSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0){
perror("Set Error");
}
bind(hSocket, (struct sockaddr *)&cli, sizeof(struct sockaddr));
int nRet = connect(hSocket,(sockaddr*)&svr, sizeof(svr));

ASP.NET TcpClient intranet

I'm developing an application in ASP.NET using Visual Basic, that have to connect to a Server in my private network.
The application must working only into my network (in future it can work on internet, too),
now I have a problem with TcpClient on ASP.NET: If I connect to the Server using an instance of IPAddress
Client = New TcpClient
Client.Connect(New IPAddress("192.168.1.12"), 6001)
the Socket try to connect to 176.64.116.11 (that's not my public IP Address...), else, if I connect to the server with a string that contains the local IP Address
Client = New TcpClient
Client.Connect("192.168.1.12", 6001)
the Socket connects succesfully but nothing responds to my command (with NetworkStream.Write and Read)
I try all of these in a Windows Application and all work succesfully.
Thanks to all
(I made any mistake in English? Ahaha, sorry :D)
PS. If you post me some code in C# don't worry, I can translate it
TcpClient has various overloads, you can give it a string containing the ip address or an IPAddress object.
Also, use
IPAddress ipAddress = IPAddress.Parse("192.168.1.12");
IPAddress does not contain a constructor that takes a string.
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.connect.aspx
As for your transmission issue; disable firewalls. Try localhost first.

Categories

Resources