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.
Related
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.
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.
Here's my code:
TcpListener listener = new TcpListener(IPAddress.Any, 0);
listener.Start();
var v = (IPEndPoint)listener.LocalEndpoint;
According to the documentation
If you do not care which local address is assigned, specify
IPAddress.Any for the localaddr parameter, and the underlying service
provider will assign the most appropriate network address. ...If you
use this approach, you can discover what local network address and
port number has been assigned by using the LocalEndpoint property.
unfortunately, the address is always 0.0.0.0.
How do I discover the actual local ip address of the TcpListener?
EDIT
The code does work for the port. v does indeed have a specific port assigned to it.
In additional to everything which Andy said about LocalEndpoint having the local address for each incoming connection, which is correct, this statement in the documentation is flat out wrong:
the underlying service provider will assign the most appropriate network address
Actually, LocalEndpoint will give you the address which the client sent the TCP SYN packet to. It will be one of your network addresses, and it will often be the one that the local routing table would choose if initiating a connection to that client address without first binding the outgoing socket to a specific local address, but it doesn't have to be.
The client, not the TCP/IP stack, selects the IP address.
FWIW, that local address could end up being any one of the addresses you find through System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces(). It is not restricted to the ones you can see through Dns.GetHostEntry(Dns.GetHostName()), although the addresses registered in DNS are the most likely to be useful on a larger network. And the list of possible addresses can change, as a result of network connections making and breaking and also as a result of dynamically assigned address (DHCP) changes.
The System.Net.NetworkInformation.NetworkChange class can be used to find out when the local address list is updated.
In the docs for IPAddress.Any, it states:
The Socket.Bind method uses the Any field to indicate that a Socket instance must listen for client activity on all network interfaces.
By simply creating a TCPListener with this property, you tell the framework that you don't care which interface it uses, just pick the best one when something connects, not before.
In order for the framework to pick the best one, it needs a client to connect to it. When something connects, it chooses the best one for that instance at that time.
The next client that connects may get the same interface, or, it could get a different one because you choose IPAddress.Any
You state it in your question:
If you do not care which local address is assigned, specify IPAddress.Any for the localaddr parameter, and the underlying service provider will assign the most appropriate network address. ...If you use this approach, you can discover what local network address and port number has been assigned by using the LocalEndpoint property.
This is what you aren't understanding:
The emphasis above talks about the LocalEndpoint of the *Socket* that is created from accepting the connection -- not the listening TCPListener.
The docs could be more clear on this point, sure -- but once you understand how listeners work, this should click.
QuickFIX/n listens to a "random" port when it establishes a connection. A quick Google search shows that QuickFIX/j has the config settings SocketLocalPort and SocketLocalHost that allows us to bind the local socket to a host/port.
Is this also possible in QuickFIX/n?
At present, I cannot see that the .NET implementation supports this configuration parameter. So the local port will always be ephemeral.
.Net
Initiator Source
Socket
Settings
I'm currently programming a UDP application which allows clients to login. After that, their endpoint gets stored in a list.
private void socket_Callback(IAsyncResult result_)
{
EndPoint remote = new IPEndPoint(IPAddress.Any, 0);
socket.EndReceiveFrom(result_, ref remote);
if (!listOfEndPoints.Contains(remote))
{
// registration process
// add it to list
listOfEndPoints.Add(remote)
}
else
{
// process packet
}
}
However, sometimes a client's NAT will assign every packet a different external end point. If the registration packet's source end point is 12.34.56.78:1000, that end point gets added to the list. If the same client then however sends another packet, the NAT will assign it a different port, so its source end point will be 12.34.56.78:1001.
This results in the server assuming the client is not registered and try to process the packet as a registration one. Needless to say this won't work.
A way of fixing this would be to send an ID (which could however be faked easily, if it's not super-cryptic) to the client. However, the client would have to add it to each packet it sends to the server.
So it wouldn't be very effective to do it like that.
Is there any other way of telling that the packet has come from the same client as the registration packet?
You should definitely not use the source IP address and port of a UDP packet to associate it with a logical connection. You should include the ID of the connection in each packet and update the IP and port you respond to if you receive a new IP and port for the same logical connection. If connection hi-jacking is an issue, you may need to implement some form of security, such as a secure checksum in the datagram.
TCP handles associating packets with connections for you. With UDP, you must associate datagrams with logical sessions yourself. I don't know why you think it "wouldn't be very effective to do it like that".
One of the tradeoffs of UDP is that if you need anything TCP provides, you have to code it yourself.
By the way, I've never seen ports shift in this way. Are you sure the client code isn't broken, perhaps opening a new socket for each datagram it sends.