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

Click For Summary
SUMMARY

The forum discussion revolves around a client-server architecture implemented in Python, where the server listens on port 9999 and instructs the client to connect to a new port for additional connections. A race condition was identified when clients were run on different machines, leading to connection refusals due to the server not being ready to accept connections on the new port. The solution involved reordering the server's operations to ensure it listens before notifying the client to reconnect. This highlights the importance of understanding TCP/IP socket behavior in multi-client environments.

PREREQUISITES
  • Understanding of TCP/IP socket programming
  • Familiarity with Python 2.7 and its socket library
  • Knowledge of client-server architecture
  • Experience with debugging race conditions in concurrent programming
NEXT STEPS
  • Learn about Python's socket.accept() method and its implications for multi-client connections
  • Explore debugging techniques for race conditions in concurrent applications
  • Study the behavior of TCP/IP sockets in different operating systems, particularly *NIX and Windows
  • Investigate tools like tcpdump and Wireshark for network traffic analysis
USEFUL FOR

Software developers, particularly those working with network programming in Python, system architects designing client-server applications, and anyone interested in debugging concurrency issues in socket communication.

cpscdave
Messages
402
Reaction score
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:)
 
Technology news on Phys.org
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   Reactions: FactChecker and 1oldman2
Its like counting your chickens before they hatch...
 
Ibix said:
"but all the faults are intermittent..."

Great... I"m going to have nightmares now about this...
 
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
 
Just running it off of windows 7, written in python.

I'll try that out tomorrow rbelli1 and see if it works.
 
rbelli1 said:
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.
 
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.
 
cpscdave said:
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
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
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 let's 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
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
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
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
You need to learn how to use tcpdump and wireshark, these are some of the most important tools in LAMP.
 
  • #16
"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
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
cpscdave said:
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.
 

Similar threads

  • · Replies 17 ·
Replies
17
Views
3K
  • · Replies 2 ·
Replies
2
Views
2K
  • · Replies 2 ·
Replies
2
Views
10K
  • · Replies 6 ·
Replies
6
Views
3K
  • · Replies 4 ·
Replies
4
Views
2K
  • Sticky
  • · Replies 48 ·
2
Replies
48
Views
68K
  • · Replies 12 ·
Replies
12
Views
6K
  • · Replies 19 ·
Replies
19
Views
9K
  • · Replies 4 ·
Replies
4
Views
4K