0

I have 2 instances of the same application, on different machines, that should talk with each other, where no one is a typical server or client.

Both instances of the application has a TcpListener, local port = 8000.

One application instance (call it "A") creates a TcpClient. Now, this client can't have local port = 8000, or the constructor throws the socket exception "Only one usage of each socket address (protocol/network address/port) is normally permitted".

So, I create this first client with a random local port, and run Connect() to connect with the other application instance "B".

"B" accepts the connection using TcpListener.AcceptTcpClient(), which returns a TcpClient that can be used to communicate with "A". Though, this TcpClient has the same IP and Port as the TcpListener!? How is this possible, when I could not use the same port when I created the TcpClient manually on "A"? I actually really would like them to use the same port as the listener, on both machines...

So, how can I create the TcpClient on "A" with same port as the TcpListener?

shadow_map
  • 313
  • 3
  • 15
  • 1
    Please show the exact code you were using that failed. – Jon Skeet Sep 03 '13 at 14:53
  • 1
    Coincidentally I just explained a lot of this: http://stackoverflow.com/a/18594031/122718 You are confusing sockets that are just opening a port with sockets that are associated with a connection. There are two kinds of sockets. – usr Sep 03 '13 at 15:19
  • Thanks, usr. Your explanation in the other thread helped a lot. – shadow_map Sep 03 '13 at 16:31

3 Answers3

3

I think you might not fully understand the address port client server architecture.

TcpListener is listening to any connection on address and port. After connection established you can use the "Socket" to receive and send messages from the client and server both.

example:

0.0.0.1 is machine A.

0.0.0.2 is machine B.

you can put a TcpListener that is listening on port 8000 on machine A. When the TcpClient on machine B will make try to connect machine A on port 8000 the TcpClient on machine B will get a generated (by the OS) port.

and then you will have a connection

0.0.0.1:8000 -> 0.0.0.2:3587(Generated port) - so you dont need to worry for the client listening port.

Niv Penso
  • 333
  • 3
  • 17
1

A TCP Connection has always a server and a client side. The server is listening (waiting) for a connection and the client connects to the server.

When the server gets the connection request, AcceptTcpClient gives you the socket of the server side to communicate with the client. A TCP Connection is always defined with the IP Addresses and Ports of the two sides: serverip:serverport and clientip:clientport.

If you want a really symmetrically System, both instances would have a server and a client that connects to the other server. All data that would then always be sent from client to server over the connection that was established by the client.

For Example:

ClientA connects to ServerB -> ConnectionAB
ClientB connects to ServerA -> ConnectionBA
ApplicationA sends data to ApplicationB over ConnectionAB
ApplicationB sends data to ApplicationA over ConnectionBA
Roland Bär
  • 1,720
  • 3
  • 22
  • 33
  • Thanks. I think I get it. I guess what I tried to accomplish was kind of a server-server communication, where both underlying server sockets of the TcpListeners should communicate with each other. So, I guess if I do like your model, on ApplicationA I would need to have a ClientA on a separate local port from ServerA, and could use ClientA for outgoing communication, and ServerA for incoming. Also, ApplicationB can not know the port of ServerA without ClientA explicitly sending a message to ServerB containing the port number (so that ClientB knows what port to connect to for ServerA), right? – shadow_map Sep 03 '13 at 16:27
  • Allmost right :-) Typically you don't specify the client port explicit but let the operating system decide which port to use. In my example of the symmetrical system I expected that you configure on both applications how to reach the other application (server ip and port), therefore there would be no need to pass the configuration of server B to Application A. If you would implement a mechanism like this you have already a asymmetrical system and therefore I would recommend to define Application A as server and Application B as client. – Roland Bär Sep 04 '13 at 06:52
0

If your goal is to use 2 TCP endpoints to talk to each other, without one of them being an explicit server always, you probably should run a listener (on port 8000, in your case) on both machines. Next, let each machine try randomly for the connection -- let each machine pick a random time (between 0 and T) and then wake up. Whichever machine wakes up first, will call connect() and establish the connection.

As @nivpenso pointed, the end point doing the connect need not explicitly bind to a port. The connect() step explicitly assigns a temporary random port to that end point.

So, if hostA initiates the connection, here are all the endpoints you would see (you can use netstat to see these connections) HostA: -- listener: 8000 -- connection to hostB:port8000, localport:xyz

HostB: -- listener: 8000 -- connection to hostA:port:xyz, localport:8000

On the other hand, if hostB initiates the connection, here are all the endpoints you would see: HostA:

-- listener: 8000
-- connection to hostB:port:xyz', localport:8000

HostB:

 -- listener: 8000
    -- connection to hostA:port8000, localport:xyz'

In the Internet, BGP uses a similar method to connection 2 TCP peers.

Manoj Pandey
  • 4,528
  • 1
  • 17
  • 18