Search code examples
socketsdelphitcp

How to connect to a specific computer that has the same External-IP as another one?


Imagine the following situation regarding a remote-access application.

I have two Server-Client applications and one Server-only application(uses a Dynamic DNS).

When I start my (1)Server-Client application it immediately connects to the Server and shows it's ID/Password/IP/Port in a ListView so when I start my (2)Server-Client application and I press connect it goes through each ID/Password/IP/Port element on the server ListView and brings me the IP/Port regarding the ID/Password.

The problem is that all these applications are using the same External-IP/Port so my application doesn't know on which computer to connect.

I've already posted this question here but it lacked detail so it got deleted. I'm posting it again and I'll also provide some code.

At first I though I need a DNS service for each Server-Client but that was just too messy and wouldn't probably help me(I was going to try to use IndyDNSServer and IndyDNSResolver components).

After I posted my problem here the first time a user told me to try and use the TCustomWinSocket

Data property ->

http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/ScktComp_TCustomWinSocket_Data.html

But I couldn't get anywhere with it.

//This block here passes the IP/Port configuration to the other 
application socket (ClientS stands for ClientSocket[Number]).

ClientS2.Host := ClientS1.Host;
ClientS2.Port := ClientS1.Port;
ClientS3.Host := ClientS1.Host;
ClientS3.Port := ClientS1.Port;
ClientS4.Host := ClientS1.Host;
ClientS4.Port := ClientS1.Port;
ClientS5.Host := ClientS1.Host;
ClientS5.Port := ClientS1.Port;
ClientS6.Host := ClientS1.Host;
ClientS6.Port := ClientS1.Port;

MyFirstBmp := TMemoryStream.Create;
MySecondBmp := TMemoryStream.Create;
MyCompareBmp := TMemoryStream.Create;
PackStream := TMemoryStream.Create;
iSendCount := 0;
StatusBar1.Panels.Items[1].Text := 'Connected';
Timer2.Enabled := true;
BitBtn1.Enabled := false;
edtIPAddr.Enabled := false;
edtPort.Enabled := false;
edtPassword.Enabled := false;
edtName.Enabled := false;
frmCConectaNovaTela.bbtConecta.Enabled;

Sleep(1000);
Socket.SendText('<|MAIN|>');  // This text makes it so that the Main 
thread on the server application be created.

I'm trying to figure out a way to make my application connect to a specific computer that has the same External-IP as other computers in the same network that are also using my application and have the same listen Ports on their ServerSockets.

In an ideal word I would have something like...

CS1.Host := '188.156.124.111';
CS1.Port := '32500';
CS1.Property := 'ThirdParameterToMakeADistinctConnection';

Solution

  • As I'm sure I told you before, you can't use just an IP alone to identify specific parties. It is just not unique enough.

    You can use the TCustomWinSocket.Data property to track whatever user-defined data you want. For example, when a client logs in to your server, you can store its public IP/Port for inbound connections, it's unique ID (username, etc), and so on.

    When a client wants to send a message to another client, it can ask the server to relay the message to the desired ID. The server can look for the ID in its clients list and then relay the message if found.

    When you have devices that are behind a router, in order to make an inbound connection to a specific device from an outside network, the router must have port forwarding enabled, where it opens a public port that forwards all received traffic to the device's private LAN IP/port.

    For peer-to-peer connections, client 1 should send a message to client 2 asked it to open a listening port, and then client 2 should reply with the public IP/port that client 1 can then connect to.

    If client 2 is behind a router, it needs to open a listening port locally as normal, but then reply with the appropriate public forwarding IP/port that is open on the router. It can use uPNP to ask the router to open a forwarding port dynamically (if the router does not support uPNP, the forwarding port must be configured statically beforehand by the router admin).

    If the connection fails, have the clients reverse roles, where client 2 then asks client 1 to open a listening port for client 2 to connect to.