2

The issue I have is that my chat client is supposed to recieve and print data from server when the server sends it, and then allow the client to reply.

This works fine, except that the entire process stops when the client is prompted to reply. So messages pile up until you type something, and after you do that, then it prints all the recieved messages.

Not sure how to fix this, so I decided why not have the client's time to type a reply timeout after 5 seconds, so that the replies can come through regardless. It's pretty flawed, because the input will reset itself, but it works better anyways.

Here's the function that needs to have a timeout:

# now for outgoing data
def outgoing():
    global out_buffer
    while 1:
        user_input=input("your message: ")+"\n"
        if user_input:
            out_buffer += [user_input.encode()]
#       for i in wlist:
            s.send(out_buffer[0])
            out_buffer = []

How should I go about using a timeout? I was thinking of using time.sleep, but that just pauses the entire operation.

I tried looking for documentation. But I didn't find anything that would help me make the program count up to a set limit, then continue.

Any idea's about how to solve this? (Doesn't need to use a timeout, just needs to stop the message pileup before the clients reply can be sent) (Thanks to all who helped me get this far)

For Ionut Hulub:

from socket import *
import threading
import json
import select
import signal # for trying to create timeout


print("client")
HOST = input("connect to: ")
PORT = int(input("on port: "))

# create the socket
s = socket(AF_INET, SOCK_STREAM)
s.connect((HOST, PORT))
print("connected to:", HOST)

#--------- need 2 threads for handling incoming and outgoing messages--

#       1: create out_buffer:
out_buffer = []

# for incoming data
def incoming():
    rlist,wlist,xlist = select.select([s], out_buffer, [])
    while 1:
        for i in rlist:
            data = i.recv(1024)
            if data:
                print("\nreceived:", data.decode())

# now for outgoing data
def outgoing():
    global out_buffer
    while 1:
        user_input=input("your message: ")+"\n"
        if user_input:
            out_buffer += [user_input.encode()]
#       for i in wlist:
            s.send(out_buffer[0])
            out_buffer = []

thread_in = threading.Thread(target=incoming, args=())
thread_out = threading.Thread(target=outgoing, args=())
thread_in.start() # this causes the thread to run
thread_out.start()
thread_in.join()  # this waits until the thread has completed
thread_out.join()
Micrified
  • 3,338
  • 4
  • 33
  • 59
  • Why are you using `input` instead of `raw_input`? `input` implicitly uses and `eval`, so it's counter-intuitive as well as unsafe. If you want a string, you should use `raw_input`. – Kyle Strand Mar 09 '13 at 22:30
  • @Kyle Strand Can't use raw_input in Python 3.1, or the version I use. Can you explain the risk? I've never really known why people say not to use it. – Micrified Mar 09 '13 at 22:32
  • Ah, sorry, didn't realize you were using Python 3, in which `input` replaces Python 2's `raw_input`, and there's no equivalent (as far as I know) for Python 2's unsafe `input`. – Kyle Strand Mar 09 '13 at 22:34
  • You need two threads. One will read data form the server and write it to the screen, and one will read input from the user and send it to the server. Look up the `threading` module in the documentation. – Ionut Hulub Mar 09 '13 at 22:38
  • Actually, according to the answer here, you don't explicitly need to handle threading for this. http://stackoverflow.com/questions/3471461/raw-input-and-timeout (Note that it'll take a bit of adjusting for Python 3, but I'd think it should work in about the same way.) Also, for your own information regarding why `eval` is dangerous: http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html – Kyle Strand Mar 09 '13 at 22:39
  • @IonutHulub I have two threads, it doesn't help. It won't print any replies until the input has been entered and sent. – Micrified Mar 09 '13 at 22:46
  • it will if you print in one thread and read in some other. – Ionut Hulub Mar 09 '13 at 22:47
  • @Ionut Hulub That is how it is set up right now, if you want I can provide a link to my code right now, or update my post with the full thing – Micrified Mar 09 '13 at 22:55
  • @IonutHulub got it, its added to my post. – Micrified Mar 09 '13 at 23:15
  • 1
    I can't test that code cause I don't have the server but here is an example that proves that you can write and read at the same time using two threads: http://pastebin.com/u86Gf8L4 The problem must be somewhere else. – Ionut Hulub Mar 09 '13 at 23:22
  • @Ionut Hulub Noo... I have no way of knowing how to fix the server.. I'm in a deep mess now. If you have the time, or if you feel like it, could you please tell me what's wrong with my server if it's the cause? Here's the [server](https://docs.google.com/file/d/0BwYE5uc9NjE-ZWFZMHJhTGJYa2s/edit?usp=sharing) – Micrified Mar 09 '13 at 23:30
  • Gonna sleep now, t - 8 hours. – Micrified Mar 09 '13 at 23:43
  • I don't know what you problem is really... cause I just tested the server with two clients connected to it and as soon as I send a message from one client I get the message on the other, even if it is send while typing in the other one. – Ionut Hulub Mar 09 '13 at 23:47
  • @Ionut Hulub huh... weird – Micrified Mar 10 '13 at 08:44

1 Answers1

0

We can use signals for the same. I think the below example will be useful for you.

import signal

def timeout(signum, frame):
    raise Exception

#this is an infinite loop, never ending under normal circumstances
def main():
    print 'Starting Main ',
    while 1:
        print 'in main ',

#SIGALRM is only usable on a unix platform
signal.signal(signal.SIGALRM, timeout)

#change 5 to however many seconds you need
signal.alarm(5)

try:
    main()
except:
    print "whoops"
A R
  • 2,697
  • 3
  • 21
  • 38