Strange things are done in the midnite sun by those who thread

  • Thread starter cpscdave
  • Start date
  • #1
402
120
SO fun story, I'm working on a client server dealio!

The flow of operations should be:
Server listens on port 9999
Client connects to port 9999
Server tells Client to connect to new port # (to allow for more connections)
Server launches a thread and listens on new port #
Client disconnects from 9999 and connects to new port number
PROFIT!

I had originally got this all working where the client and the server were on the same computer.
Today I decided to start to run the clients on a different computer.

So the client connected to 9999
got the message to use the new port number
and then would get a connection refused on the reconnect. This happened like 90-95% of the time.. But occasionally just occasionally it would work??

Fast forward an hour of scratching my head trying to figure out what the heck is going on. Turns out when I ran the client on this computer the the client would run just slow enough for the server to launch the thread and listen.

When I ran it on the other laptop it was trying to connect before the listen was done on the server.
A simple reordering so the server listens before telling the client to reconnect and everything works fine!

Fun times:)
 

Answers and Replies

  • #2
Ibix
Science Advisor
Insights Author
2020 Award
7,393
6,474
Ain't race conditions fun to debug?

You know the story about the engineer who goes to hell? The Devil shows him a room full of electronic items and says his punishment is to fix them. The engineer doesn't think that's too bad. "Ah", says the Devil, "but all the faults are intermittent..."
 
  • Like
Likes FactChecker and 1oldman2
  • #4
402
120
"but all the faults are intermittent..."
Great... I"m going to have nightmares now about this....
 
  • #5
rbelli1
Gold Member
988
377
Once you accept the TCP/IP socket the original port will be available for connection. You don't need to corral the client to another port. At least this is true of *NIX and Windows servers and almost everything internet facing. What operating system are you using?

BoB
 
  • #6
402
120
Just running it off of windows 7, written in python.

I'll try that out tomorrow rbelli1 and see if it works.
 
  • #7
12,492
6,281
Once you accept the TCP/IP socket the original port will be available for connection. You don't need to corral the client to another port. At least this is true of *NIX and Windows servers and almost everything internet facing. What operating system are you using?

BoB
I don't think this is right. If your program connects does its business and then disconnects then the port is available. Web applications do this.

However, if this is a strict client/server connection sing say Java with multiple clients then you might need to use the OP's scheme of port reassignment to allow each client to keep the port open.
 
  • #8
rbelli1
Gold Member
988
377
I've written server apps and I just listen on a particular port and then accept. No further connection is required. The listening socket is re-enabled for more connections.

Think about how a web server works. Thousands of clients connect at the same time to the same port. If everyone had to wait for a transaction to occur then the web would screech to a halt. As I type I have a persistent connection to physicsforums:https. Presumably I am not the only one able to access this site.

BoB

edit: and wordpress:https and a number of Microsoft servers and some that can't do reverse dns.
 
  • #9
Ibix
Science Advisor
Insights Author
2020 Award
7,393
6,474
Great... I"m going to have nightmares now about this....
Sorry. :wink: I agree with rbelli1, by the way. I may be able to dig out some elderly python code to illustrate this - I'll have a look.
 
  • #10
Ibix
Science Advisor
Insights Author
2020 Award
7,393
6,474
As promised, here's a not-terribly-good chat server and client. Start the server first, and 2+ instances of the client. Just type at the prompt in the client command windows and hit enter to broadcast. The next time you type something and hit enter in any other client window, everything that has been said by anybody since the last time you typed will appear. It's functional as a use of sockets (which was the point of this), but not really as an actual chat client. Note that the server simply retains the connection returned by socket.accept() - there's no disconnect-and-reconnect.

Note also that it's slightly elderly python 2.7 - I don't know how much difference that might make to sockets.

Server:
Python:
import socket

def notifyAll(conns,c,data):
   for conn in conns:
     if len(conn)==3 and conn[1]!=c[1]:
       print "...notifying "+conn[2]
       conn[0].sendall(data+"\n")

HOST=""
PORT=12345

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.setblocking(0)
s.bind((HOST,PORT))
s.listen(1)
connections=[]
gotConnection=False
while True:
   # See if any new clients want to connect
   try:
     conn,addr=s.accept()
     print 'Connected by', addr
     conn.setblocking(0)
     connections.append([conn,addr])
     gotConnection=True
   except:
     pass
   # Print any data and close the connection if a QUIT was received
   for conn in connections:
     try:
       dataLine=conn[0].recv(1024)
       if dataLine=="QUIT":
         print conn[2]+" quit"
         connections.remove(conn)
         notifyAll(connections,conn,conn[2]+" quit\n")
       elif len(conn)==2:
         print str(addr)+" is called "+dataLine
         conn.append(dataLine)
         notifyAll(connections,conn,conn[2]+" joined\n")
       else:
         print "Received from "+conn[2]+": "+dataLine
         notifyAll(connections,conn,conn[2]+": "+dataLine+"\n")
     except:
       pass
   # Quit if all connections have been closed
   if gotConnection and len(connections)==0:
     break
s.close()
Client:
Python:
import socket

HOST="localhost"
PORT=12345
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((HOST,PORT))
s.setblocking(0)
inputLine=raw_input("Please enter your name: ")
while True:
   s.sendall(inputLine)
   try:
     while True:
       dline=s.recv(1024)
       print dline
   except:
     pass
   if inputLine=="QUIT":
     break
   inputLine=raw_input("> ")
s.close()
 
  • #11
402
120
I looked at my code yesterday and decided it was too complex to try and test it without changing the ports. One of those if its working lets not break it situations :)

But out of curiosity if you have multiple clients connecting from the same IP and to the same port, how does the OS/Python determine which connection to send the data to?
 
  • #12
rbelli1
Gold Member
988
377
The port at the client end is different for each connection. When the client opens the port it gets a local port assigned by some OS defined method.

Server side -->> Client side
192.168.1.1:80 -->> 192.168.1.2:1234
192.168.1.1:80 -->> 192.168.1.2:1235
192.168.1.1:80 -->> 192.168.1.2:1236
and possibly other computers on the network
192.168.1.1:80 -->> 192.168.1.3:1234
192.168.1.1:80 -->> 192.168.1.4:1234
192.168.1.1:80 -->> 192.168.1.5:1234

BoB
 
  • #13
Ibix
Science Advisor
Insights Author
2020 Award
7,393
6,474
If you run the code I posted you'll see that addr, the second variable returned by socket.accept, is what rbelli1 is describing, encoded as a two element tuple.
 
  • #14
402
120
Yes I forgot about the src port.

I'm now not sure how I got the model of being pushed to a different port in my brain hole.
 
  • #15
1,524
624
You need to learn how to use tcpdump and wireshark, these are some of the most important tools in LAMP.
 
  • #16
Svein
Science Advisor
Insights Author
2,129
686
"accept() is used on the server side. It accepts a received incoming attempt to create a new TCP connection from the remote client, and creates a new socket associated with the socket address pair of this connection." See https://en.wikipedia.org/wiki/Berkeley_sockets
 
  • #17
402
120
I'm going to have to go through my notes from the networking class I took.

I'm confused as to how I got in my mind that for example.
Apache2 listened on port 80, and then upon a connection forked itself and pushed the connection to a different random socket # to handle the session.
 
  • #18
1,524
624
I'm going to have to go through my notes from the networking class I took.

I'm confused as to how I got in my mind that for example.
Apache2 listened on port 80, and then upon a connection forked itself and pushed the connection to a different random socket # to handle the session.
Sort of. When a process listens on a port and allows multiple connections there are two ways that it handles it. It can actually handle many connections to the same socket because the source ip is always different (this is TCP specific) so it can filter and send things to the right socket.

The only time it pushes the connection somewhere random is when you have multiple connections from the same machine.
 

Related Threads on Strange things are done in the midnite sun by those who thread

Replies
32
Views
4K
Replies
4
Views
2K
  • Last Post
Replies
1
Views
626
Replies
3
Views
3K
  • Last Post
Replies
4
Views
2K
  • Last Post
Replies
7
Views
2K
Replies
8
Views
1K
  • Last Post
Replies
22
Views
4K
Top