I am trying to accomplish Tcp hole punching with socket option as reuse address.
First step- Run and tcp listener in server S with active open tcp port 8001.
Second step- Run a Tcp socket with reuse address(method name is enableReuseAddres(Socket sck) mentioned below) in socket option on client A which is behind the NAT on port 8001.
Third step- Connect A => S.
Fourth step- Send data from A => S and get confirm data from S => A.
Fifth step- Get remote endpoint of A which is X.X.X.X:8001(External IP and Port of A).
Sixth Step- Listen on a socket with port 8001(method name is runServer mentioned below),in client A with reuse address(method name is enableReuseAddres(Socket sck) mentioned below) in socket option.
Disclaimer:- No error found and able to bind the same endpoint which is used to connect to the server S with the help of ReuseAddress and able to listen on the same port 8001.
But when I try to check the port 8001 is opened or closed I always get port is closed,of client A.
public void runServer()
{
Socket sk = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
enableReuseAddres(sk);
sk.Bind(loclEP);
sk.Listen(1);
var connection_socket = sk.Accept();
MessageBox.Show("Connected");
}
IPEndPoint loclEP = new IPEndPoint(IPAddress.Any, 8001);
public void enableReuseAddres(Socket sck)
{
sck.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReuseAddress, true);
sck.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.KeepAlive, true);
}
Related
I have a UDP Socket connection working between devices with local IPs (192.168.x.x), that I want to switch to a connection with an external server, with the following configuration:
Create socket
private Socket _socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
private const int bufSize = 4096 * 4;
private State state = new State();
private EndPoint epFrom = new IPEndPoint(IPAddress.Any, 0);
private AsyncCallback recv = null;
private static int PORT = 27000;
Openning device as a server to listen through the socket
_socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.ReuseAddress, true);
_socket.Bind(new IPEndPoint(IPAddress.Any, port));
Receive(); // Function to receive datagrams through the socket, irrelevant to this issue
Connect socket to remote endpoint
// {address:port} of an external server
_socket.Connect(new IPEndPoint(IPAddress.Parse(address), port));
Send data to socket
_socket.BeginSend(data, 0, data.Length, SocketFlags.None, (ar) =>
{
try
{
_socket.EndSend(ar);
}
catch (Exception ex)
{
Console.WriteLine("[UDP] Error Send: " + ex.ToString());
}
}, state);
The code above works fine for local IP addresses, the problem came when trying to use as a remote ip endpoint a public IP of a remote server.
The datagram seemed to be sent but it never arrived to the server. I tried to connect the phone to a VPN and the local IP changed from a 192.168.x.x to a 10.0.x.x, and then the connection to the external server worked.
Therefore, connection with an external IP only worked when the device's IP was a private IP of class A, but it didn't work with a class C range (https://www.meridianoutpost.com/resources/articles/IP-classes.php).
I want to find a solution to be able to connect to external IP address without having to connect a third party VPN software.
If someone has the same question, I have already solved it.
To access external IPs with local class C IPs and no VPN you should do UDP hole punching instead of trying to establish a connection.
Erase the .Connect() and the .Bind() methods, and, instead of using BeginSend/EndSend, use the SendTo or SendToAsync methods with the server's public IP as the endpoint destination.
Additionally, I recommend changing:
SocketOptionName.ReuseAddress
to:
SocketOptionName.PacketInformation
I'm trying to make two applications. One will be sending data to a specific udp port, and the other will be reading it.
I am having 2 problems:
when running on the same machine, I get an error: "Only one usage
of each socket address (protocol/network address/port) is normally
permitted" so I need to figure out how to test it if I cannot have
multiple socket connections at the same port.
when I tried using
an internal ip of another computer within my network, I did not get
any reading at all.
server:
private Socket sock;
private const int PORT = 5000;
public void start()
{
sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
sock.ReceiveTimeout = 1;// seconds
sock.SendTimeout = 1;// seconds
IPEndPoint iep = new IPEndPoint(IPAddress.Any, PORT);
EndPoint ep = (EndPoint)iep;
sock.Bind(iep);
MulticastView view_obj = new MulticastView();
while(true)
{
try
{
if (sock.Connected)
{
sock.Send(Serializer.ObjectToByteArray(view_obj));
}
}catch(Exception ex){
Console.WriteLine(ex);
}
Thread.Sleep(1000); // milliseconds
}
}
client:
IPAddress ip = IPAddress.Parse("127.0.0.1");
IPEndPoint iep = new IPEndPoint(ip, PORT);
EndPoint ep = (EndPoint)iep;
UdpClient client = new UdpClient(PORT);
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
// or using: Byte[] receiveBytes = client.Receive(ref ep);
Byte[] receiveBytes = client.Receive(ref RemoteIpEndPoint);
MulticastView view;
view = (MulticastView)Serializer.ByteArrayToObject(receiveBytes);
Note that I need separate apps (on separate processes).
You can't have 2 separate sockets open on the same IP address / port. Each IP/Port is a unique mailbox, so to speak. (Technically, it is possible to have 2 processes attached to the same socket, under certain circumstances, but that isn't relevant to your problem). The rule is simple, but the workarounds are several.
I would ask if the client really needs to have a standard port number. Normally, UDP/TCP clients just use a random socket and communicate with the server. The server is usually the only side of the connection that needs a standard, fixed port. The UdpClient.Receive() method will populate the IPEndPoint with the ip/port of the sender of the packet so that you can reply to it.
Either don't bind to IPAddress.Any (that causes it to bind to all interfaces). Replace the Any with a specific IP address (one machine can have multiple if you setup IP aliasing or multiple adapters), or simpler, change the port number of the client to differ from the server. You should be able to bind one end to the primary ethernet interface IP address, and bind the client to the loopback (127.0.0.1) address.
Even though this is an old question, I think it would be good to point out an exception to the one port rule.
If you are using multicast (which is UDP to a multicast address), you can set the SO_REUSEADDR option to use the port for multiple sockets.
I am trying to send strings to a server using Synchronous WebSockets in a C# console application. The following code works flawlessly on 127.0.0.1 but doesn't work on any real server I tried. The result I get is that the client connects to the IP/Port and sends strings with no errors, but _serverSocket.Accept(); never triggers when _clientSocket.Connect(_IP, _PORT); is called.
Also, if serverSocket.Bind(new IPEndPoint(IPAddress.Any, _PORT)); is not called, then the sender gets an error (as expected) when trying to connect. So it seems like it should work and the port is also working.
I tried using a variety of servers. The one in the sample code below is taken from https://server.pro/
So, the question is, why doesn't _serverSocket.Accept(); trigger, since the sender can connect and send strings with no errors ?
private static Socket _serverSocket, _clientSocket;
private const int _PORT = 40288;
//this IP doesn't work, but 127.0.0.1 works flawlessly
private static IPAddress _IP = IPAddress.Parse("37.187.143.226");
//---------sender (client) code---------
_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.Tcp);
//connects, no errors appear
_clientSocket.Connect(IPAddress.Parse(_IP), _PORT);
//sends strings to the server, no errors appear
while (true) {
Console.Write("Enter text to send: ");
string input = Console.ReadLine();
_clientSocket.Send(Encoding.ASCII.GetBytes(input));
Console.WriteLine("Sent!");
}
//-------listener (server) code--------
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.Tcp);
_serverSocket.Bind(new IPEndPoint(IPAddress.Any, _PORT));
_serverSocket.Listen(10);
Console.WriteLine("Waiting for a client socket to connect");
_clientSocket = _serverSocket.Accept(); //never triggers
Console.WriteLine("Socket accepted, waiting for data...");
The server code must run on the machine that you want to connect to. That would be the machine that has IP 37.187.143.226.
So either run everything locally and use target IP "localhost" or run the server on that other box and use the 37 IP.
Also be aware that often firewalls and routers must be configured to allow access.
I have several LANs(10.0.0.x) connected to a WAN(192.168.1.x). Each through a router that allows a network directed broadcast. This is to allow the devices in the LANs to be discovered by devices on the WAN.
I can send a broadcast on the LAN(10.0.0.255) and receive it on my socket. But when I move to the WAN I can see it in wireshark, but not my socket. I other words I have a device with address 10.0.0.1 sending the same message to 192.168.1.255 through a gateway but my socket is not receiving it. When this happens the source address is the address of the router. Here is the code for my socket:
udpSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp);
//Assign the any IP of the machine and listen on port number 5000
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 5000);
//Bind this address to the server
udpSocket.Bind(ipEndPoint);
IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 5000);
//The epSender identifies the incoming clients
EndPoint epSender = (EndPoint)ipeSender;
//Start receiving data
udpSocket.BeginReceiveFrom(byteData, 0, byteData.Length,
SocketFlags.None, ref epSender, new AsyncCallback(ReceiveAnnounce), epSender);
I have a wireshark trace for each message but I'm not sure the best way to post it. Thanks.
Do you understand that UDP provides no guarantee that a packet will be received? (TCP uses a client to server connection) and that packets are broadcast to a 'multicast group' (this resembles an IP-address but must be in the range 224.0.0.0 to 239.255.255.255) rather than to an IP.
Your use of IPAddress.Any tells it to use all network interfaces, but you never tell it which multicast group to use, I've never done this in C# myself, however it appears you want to add this line of code before your BeginReceiveFrom;
udpSocket.SetSocketOption(SocketOptionLevel.IP,SocketOptionName.AddMembership,new MulticastOption(TARGET_IP));
You should replace TARGET_IP with the address of your multicast group you wish to listen on.
I took that line of code from this site; http://osix.net/modules/article/?id=409
I been reading a lot on how to implement UDP hole punching but fore some reason I cannot make it work.
For those that are not familiar of what udp hole punching is here is my own definition:
The goal is to be able to transfer data between two clients (Client A
and client B) with the help of a server. So client A connects to the server and sends its info. Client B does the same. The server has the nessesary info so that Client A is able to send data to Client B and vise versa . Therefore the server gives that info to both clients. Once both clients have that info about each other it is possible to start sending and receiving data between those clients without the help of the server.
My goal is to be able to do what I just described (udp hole punching). Before doing so I think it will be helpful to be able to connect from the server to the client. In order to do so I plan to send the server the info about the client. Once the server receives that info attempt to connect to the client from scratch. Once I am able to perform that I should have everything I need to start implementing the real udp hole punching.
Here is how I have things set up:
The top router has the server and bottom router connected to LAN ports. The bottom router (NAT) is connected to the top router via it's WAN port. And the client computer is connected to the bottom router to one of its LAN ports.
So in that connection the client is able to see the server but the server is not able to see the client.
So the algorithm I have done in pseudo code is:
Client connects to server.
Client send some UDP packages to the server in order to open some ports on the NAT
Send information to the server on what ports the client is listening to.
Once the server receives that info attempt to connect to the client from scratch.
Here is the implementation in code:
Server:
static void Main()
{
/* Part 1 receive data from client */
UdpClient listener = new UdpClient(11000);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, 11000);
string received_data;
byte[] receive_byte_array = listener.Receive(ref groupEP);
received_data = Encoding.ASCII.GetString(receive_byte_array, 0, receive_byte_array.Length);
// get info
var ip = groupEP.Address.ToString();
var port = groupEP.Port;
/* Part 2 atempt to connect to client from scratch */
// now atempt to send data to client from scratch once we have the info
Socket sendSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint endPointClient = new IPEndPoint(IPAddress.Parse(ip), port);
sendSocket.SendTo(Encoding.ASCII.GetBytes("Hello"), endPointClient);
}
Client:
static void Main(string[] args)
{
/* Part 1 send info to server */
Socket sending_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPAddress send_to_address = IPAddress.Parse("192.168.0.132");
IPEndPoint sending_end_point = new IPEndPoint(send_to_address, 11000);
sending_socket.SendTo(Encoding.ASCII.GetBytes("Test"), sending_end_point);
// get info
var port = sending_socket.LocalEndPoint.ToString().Split(':')[1];
/* Part 2 receive data from server */
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, int.Parse(port));
byte[] buffer = new byte[1024];
sending_socket.Receive(buffer);
}
For some reason it worked a few times! It works when the client receives data successfully on the line: sending_socket.Receive(buffer);
Things to note:
If on the server on the second part I used the instance variable listner instead of creating the new variable sendSocket and send the bytes through that variable the client is able to receive the data being sent. Remember that the second part of the server is going to be implemented by a second client B that's why I am initializing variables again from scratch...
Edit:
Here is a different way of looking at the same problem. When I initialize a new object instead of using the same object the client does not receives the response.
I have a object of type UdpClient. I am able to send data with that object to the other peer. If I create another object of the same type with the same properties and attempt to send data it does not work! I might be missing to initialize some variables. I am able to set private variables with reflection so I should not have a problem. anyways here is the server code:
public static void Main()
{
// wait for client to send data
UdpClient listener = new UdpClient(11000);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, 11000);
byte[] receive_byte_array = listener.Receive(ref groupEP);
// connect so that we are able to send data back
listener.Connect(groupEP);
byte[] dataToSend = new byte[] { 1, 2, 3, 4, 5 };
// now let's atempt to reply back
// this part does not work!
UdpClient newClient = CopyUdpClient(listener, groupEP);
newClient.Send(dataToSend, dataToSend.Length);
// this part works!
listener.Send(dataToSend, dataToSend.Length);
}
static UdpClient CopyUdpClient(UdpClient client, IPEndPoint groupEP)
{
var ip = groupEP.Address.ToString();
var port = groupEP.Port;
var newUdpClient = new UdpClient(ip, port);
return newUdpClient;
}
the client code basically sends data to the server and then waits for a response:
string ipOfServer = "192.168.0.132";
int portServerIsListeningOn = 11000;
// send data to server
Socket sending_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPAddress send_to_address = IPAddress.Parse(ipOfServer);
IPEndPoint sending_end_point = new IPEndPoint(send_to_address, portServerIsListeningOn);
sending_socket.SendTo(Encoding.ASCII.GetBytes("Test"), sending_end_point);
// get info
var port = sending_socket.LocalEndPoint.ToString().Split(':')[1];
// now wait for server to send data back
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, int.Parse(port));
byte[] buffer = new byte[1024];
sending_socket.Receive(buffer); // <----- keeps waiting in here :(
note that the client is behind a router (NAT) otherwise I will not have this problem. The reason why I will like to copy udpClient is so that I can send that variable to another computer enabling the other computer to send data to the client.
So my question is why is the original object listener able to send data but newClient is not able to? The client keeps waiting at line sending_socket.Receive(buffer); even after the server executes the line: newClient.Send(dataToSend, dataToSend.Length);. the client successfully receives data when listener sends the data but not newClient. Why is this if both variables have the same destination IP and port? how do the variables differ?
Note:
If the server and client are on the same network then the copy works and variable newClient is able to send data to the client. To simulate this problem the client must be behind a NAT (router). An example of such network may consist of two routers. let's call them router X and router Y. You also need a Server call that S. and a client C. so S can be connected to one of the LAN ports of X. C can be connected to one of the LAN ports of Y. Finally connect the WAN port of Y to one of the LAN ports of X.
Hmm, I think you are confusing several things here. For one thing, it's really called UDP hole punching. Let me try to explain how this should work.
NAT routers usually do port mapping when forwarding packets from the inside private network to the outside internet.
Say you created a UDP socket on a machine behind NAT, and sent a datagram to some external IP/port. When the IP packet carrying that datagram leaves the sending machine, its IP header has the source address field set to local not-globally-routable private IP address (like 192.168.1.15), and UDP header has the source port field set to whatever port was assigned to the socket (either explicitly via binding, or implicitly picked by the OS from the ephemeral ports). I'll call this source port number P1.
Then when the NAT router sends that packet out on the outside network, it overwrites the source IP address to its own external IP address (otherwise there's no way to route packets back), and often overwrites the source UDP port to some other value (maybe because some other host on the private network uses the same source port, which creates ambiguity). The mapping between the original source port and that new port number (let's label it P2) is preserved in the router to match return packets. This mapping might also be specific to the target IP address and target UDP port.
So now you have "punched a hole" in the router - UDP packets sent back to the router to port P2 are forwarded to internal machine on UDP port P1. Again, depending on NAT implementation, this could be restricted to only packets from the original target IP address and target UDP port.
For client-to-client communication you'll have to tell external IP/port of one to the other through the server, hoping that the NAT router maps same internal source ports to same external source ports. Then the clients will send packets to each other using those.
Hope this helps.
Finally found the answer! Here is the implemenation with just a client and a server. My next attempt will be to use 3 computers. anyways hope this helps:
Server code:
class Program
{
static byte[] dataToSend = new byte[] { 1, 2, 3, 4, 5 };
// get the ip and port number where the client will be listening on
static IPEndPoint GetClientInfo()
{
// wait for client to send data
using (UdpClient listener = new UdpClient(11000))
{
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, 11000);
byte[] receive_byte_array = listener.Receive(ref groupEP);
return groupEP;
}
}
static void Main(string[] args)
{
var info = GetClientInfo(); // get client info
/* NOW THAT WE HAVE THE INFO FROM THE CLIENT WE ARE GONG TO SEND
DATA TO IT FROM SCRATCH!. NOTE THE CLIENT IS BEHIND A NAT AND
WE WILL STILL BE ABLE TO SEND PACKAGES TO IT
*/
// create a new client. this client will be created on a
// different computer when I do readl udp punch holing
UdpClient newClient = ConstructUdpClient(info);
// send data
newClient.Send(dataToSend, dataToSend.Length);
}
// Construct a socket with the info received from the client
static UdpClient ConstructUdpClient(IPEndPoint clientInfo)
{
var ip = clientInfo.Address.ToString();
var port = clientInfo.Port;
// this is the part I was missing!!!!
// the local end point must match. this should be the ip this computer is listening on
// and also the port
UdpClient client = new UdpClient(new IPEndPoint( IPAddress.Any, 11000));
// lastly we are missing to set the end points. (ip and port client is listening on)
// the connect method sets the remote endpoints
client.Connect(ip, port);
return client;
}
}
client code:
string ipOfServer = "192.168.0.139";
int portServerIsListeningOn = 11000;
// send data to server
Socket sending_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPAddress send_to_address = IPAddress.Parse(ipOfServer);
IPEndPoint sending_end_point = new IPEndPoint(send_to_address, portServerIsListeningOn);
sending_socket.SendTo(Encoding.ASCII.GetBytes("Test"), sending_end_point);
// get info
var port = sending_socket.LocalEndPoint.ToString().Split(':')[1];
// now wait for server to send data back
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, int.Parse(port));
byte[] buffer = new byte[1024];
sending_socket.Receive(buffer); // <----- we can receive data now!!!!!
Have you considered using UPnP on the client to configure NAT traversal to allow incoming packets on a particular port? The client would then only need to communicate the inbound IP and port to the server, and wait for the server to send packets.
http://en.wikipedia.org/wiki/Universal_Plug_and_Play
Seems you are able to connect with the server first time.After successful connection you need to close and disconnect the connection each time.Please check this sample code
http://codeidol.com/csharp/csharp-network/Connectionless-Sockets/A-Simple-UDP-Application/