I am creating a chat server in python and got quite far as a noob in the language. I am having 1 problem at the moment which I want to solve before I go further, but I cannot seem to find how to get the problem solved.
It is about a while loop that continues..
in the below code is where it goes wrong
while 1:
try:
data = self.channel.recv ( 1024 )
print "Message from client: ", data
if "exit" in data:
self.channel.send("You have closed youre connection.\n")
break
except KeyboardInterrupt:
break
except:
raise
When this piece of code get executed, on my client I need to enter "exit" to quit the connection. This works as a charm, but when I use CTRL+C to exit the connection, my server prints "Message from client: " a couple of thousand times.
where am I going wrong?
You're pressing Ctrl-C on the client side. This causes the server's self.channel to get closed.
Since calling recv() on a closed channel immediately returns a blank string, your server code gets stuck in an infinite loop.
To fix this, add the following line to your server code:
data = self.channel.recv ( 1024 )
if not data: break # <<< ADD THIS
Or, as suggested by #sr2222, you can combine both this and your current check into one:
if not data or 'exit' in data:
This will exit the loop if the channel has been closed.
Related
So, if i want to make a "chat" with python sockets, i need to be able to write a message and send it anytime i want, maybe by doing something like this:
while True:
msg = input()
socket.send(msg)
But, if i do that, i will not be able to use socket.recv() without making python wait for a message and stop the program until it gets received, i tried to solve this with threading but it of course can't work like that. How can i solve this?
Below the attempt by threading.
def receive():
while True:
client.recv(2048)
looprecv = threading.Thread(target=receive())
looprecv.start()
while True:
message = input("messaggio: ")
send(message)
if message == "!exit":
break
UPDATE: I found the source of the program hanging. In my pdthread it calls mysocket1.sendall(mydata). It doesn't seem to be able to get past this. Does anyone know why this might be an issue?
I have the following code:
mysocket1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mysocket1.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
mysocket1.connect(('127.0.0.1', 10001))
while mysocket1:
try:
msg = mysocket1.recv(4092)
msg = pickle.loads(msg)
print(msg)
for pd in pd_objects:
if msg[0] == pd.cam_ip and str(msg[1]) == 'ON' and pd.pd_active == False:
pd.pd_active = True
pdthread = Thread(target=get_pd_data(pd.cam_ip))
pdthread.daemon = True
pdthread.start()
print("testing1")
elif msg[0] == pd.cam_ip and msg[1] == 'OFF':
pd.pd_active = False
print("testing else")
print("testing2")
except:
traceback.print_exc(file=sys.stdout)
break
print("reached end")
I have another python program connected on the other end. This connects and runs perfectly the first time I press a button to activate it. I have my data sending over in the pdthread and all works swell. It's what happens afterwards that's the problem. Future button presses are NOT picked up by this side. The data is being sent over the socket just fine from the other end, it's just not being received here.
I've put in some prints for testing and I found a few interesting things that I cannot explain which is why I'm asking here:
The print("testing1") is never printed. Ever. Not even after the first successful click. Which makes me think that pdthread.start() is behaving like pdthread.join()... which confuses me.
The print("testing else") is never printed. This is expected given my testing but I wanted to rule it out.
Here's the weirdest one. I have two items in my pd_objects list. When I click the button that sends the pd.cam_ip of the first item, print("testing2") does not print, but it DOES print if I click the one for the second item in the list.
Can anyone help explain this bizarre behaviour?
EDIT: the final print is also never printed
def mp_worker(row):
ip = row[0]
ip_address = ip
tcp_port = 2112
buffer_size = 1024
# Read the reset message sent from the sign when a new connection is established
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
print('Connecting to terminal: {0}'.format(ip_address))
s.connect((ip_address, tcp_port))
#Putting a breakpoint on this call in debug makes the script work
s.send(":08a8RV;")
#data = recv_timeout(s)
data = s.recv(buffer_size)
strip = data.split("$", 1)[-1].rstrip()
strip = strip[:-1]
print(strip)
termStat = [ip_address, strip]
terminals.append(termStat)
except Exception as exc:
print("Exception connecting to: " + ip_address)
print(exc)
The above code is the section of the script that is causing the problem. It's a pretty simple function that connects to a socket based on a passed in IP from a DB query and receives a response that indicates the hardware's firmware version.
Now, the issue is that when I run it in debug with a breakpoint on the socket I get the entire expected response from the hardware, but if I don't have a breakpoint in there or I full on Run the script it only responds with part of the expected message. I tried both putting a time.sleep() in after the send to see if it would get the entire response and I tried using the commented out recv_timeout() method in there which uses a non-blocking socket and timeout to try to get an entire response, both with the exact same results.
As another note, this works in a script with everything in one main code block, but I need this part separated into a function so I can use it with the multiprocessing library. I've tried running it on both my local Windows 7 machine and on a Unix server with the same results.
I'll expands and reiterate on what I've put into a comment moment ago. I am still not entirely sure what is behind the different behavior in either scenario (apart from timing guess apparently disproved by an attempt to include sleep.
However, it's somewhat immaterial as stream sockets do not guarantee you get all the requested data at once and in chunks as requested. This is up for an application to deal with. If the server closes the socket after full response was sent, you could replace:
data = s.recv(buffer_size)
with recv() until zero bytes were received, this would be equivalent of getting 0 (EOF) from from the syscall:
data = ''
while True:
received = s.recv(buffer_size)
if len(received) == 0:
break
data += received
If that is not the case, you would have to rely on fixed or known (sent in the beginning) size you want to consider together. Or deal with this on protocol level (look for characters, sequences used to signal message boundaries.
I just recently found out a solution here, and thought I'd post it in case anyone else has issue, I just decided to try and call socket.recv() before calling socket.send() and then calling socket.recv() again afterwards and it seems to have fixed the issue; I couldn't really tell you why it works though.
data = s.recv(buffer_size)
s.send(":08a8RV;")
data = s.recv(buffer_size)
I coded a basic socket system with "select". I want get the list of connected clients instantly.
When the timeout of "select" has passed and several clients come after, it's the drama..
Example - Concerns:
I have 3 clients with one that connects before the timeout, 2 others are connected after the timeout, so I'm going to refresh my list if it took into account two other clients after the timeout.
1st result: I display my variable "list", I see the first socket that is connected before the timeout + one of the other socket who is connected after the timeout. Total: 2 of 3 clients
2nd result: I still re-display my variable "list", and the three clients are there ....
But I want the list without having to re-display the list every time for every customer you can imagine I have 10 clients and I have to show my liste10 times
So I thought to use the asyncore module who is more fluid, what do you think? Do you have a solution for me (easier)? Should I use the multi-threading or stayed on asyncore or select module?
EDIT CODE SOURCE:
import socket, select
hote = ''
port = 81
mainConnection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mainConnection.bind((hote, port))
mainConnection.listen(5)
print("Listen to {}".format(port))
client_online = []
while True:
connection_access, wlist, xlist = select.select([mainConnection], [], [], 10)
for connexion in connection_access:
connection_client, infos_connexion = connexion.accept()
client_online.append(connection_client)
refresh = input(">>> ")
while True:
try:
refresh = int(refresh)
except ValueError:
print("Not allowed")
refresh = int(refresh)
else:
break
if refresh == 1:
print("List client : {}".format(client_online))
There are three major problems with your code:
You call input in your loop. This function will block until ENTER is pressed.
If a non-integer is input from the console, you will get an exception. You handle that exception, but you handle it wrongly. Instead or asking for input again, you simply try to perform the same operation that caused the exception again.
You only check for incoming connection in your select call. You never check if any of the connected sockets have sent anything.
The major problem here for you is the call to input as it will completely stop your program until input from the console is entered.
Your post is very unclear but I can tell you that the problem is that you aren't understanding how to use select.
The code you posted only calls select one time. The program gets to the select() call and waits for mainConnection to be readable (or for the timeout). If mainConnection becomes readable before the timeout, select() returns with one readable file descriptor which you then process in your for loop. But that's it. select is never called again and so your program never checks for any more incoming connections.
In almost every application select should be in a loop. Each time through the loop the program waits in the select() call until one or more sockets is ready for reading or writing. When that happens, select gives you the file descriptors that are ready and it's your job to have other code actually do something. For example, if select returns a socket's file descriptor as readable it's your job to call .recv() on that socket.
You can certainly use asyncore. In fact, I think you should study the source code for asyncore to learn how to properly use select.
I'm new to socket programming (and somewhat to Python too) and I'm having trouble getting the select timeout to work the way I want to (on the server side). Before clients connect, timeout works just fine. I give it a value of 1 second and the timeout expires in my loop every 1 second.
Once a client connects, however, it doesn't wait 1 second to tell me the timeout expires. It just loops as fast as it can and tells me the timeout expires. Here's a snippet of my code:
while running:
try:
self.timeout_expired = False
inputready, outputready, exceptready = select.select(self.inputs, self.outputs, [], self.timeout)
except select.error, e:
break
except socket.error, e:
break
if not (inputready):
# Timeout expired
print 'Timeout expired'
self.timeout_expired = True
# Additional processing follows here
I'm not sure if this is enough code to see where my problem is, so please let me know if you need to see more. Basically, after a client connects, it at least appears that it ignores the timeout of 1 second and just runs as fast as it can, continuously telling me "Timeout expired". Any idea what I'm missing?
Thanks much!!
Edit: I should clarify..."inputready" represents input from a client connecting or sending data to the server, as well as stdin from the server. The other variables returned from select are only server-side variables, and is what I'm trying to do is detect whether the CLIENT took too long to reply, so I'm only checking if inputready is empty.
It is only a timeout if inputready, outputready, and exceptready are ALL empty. My guess is you have added the client socket to both self.inputs and self.outputs. Since the output socket is usually writable, it will always show up in outputready. Only add the client socket to self.outputs if you are ready to output something.
"When the timeout expires, select() returns three empty lists.
...To use a timeout requires adding the extra argument to the select() call and handling the empty lists after select() returns."
readable, writable, exceptional = select.select(inputs, outputs, inputs,timeout)
if not (readable or writable or exceptional):
print(' timed out, do some other work here', file=sys.stderr)
[https://pymotw.com/3/select/index.html][1]