2009-12-21 172 views
3

目前,我正在嘗試使用Python中的套接字(一種雙用戶聊天系統)做一個小型項目。Python:同步線程之間的輸入和輸出

import socket 
import threading 

#Callback. Print doesn't work across threads 
def data_recieved(data): 
    print data 

#Thread class to gather input 
class socket_read(threading.Thread): 
    sock = object 
    def __init__(self, sock): 
     threading.Thread.__init__(self) 
     self.sock = sock 
    def run(self): 
     while True: 
      data = self.sock.recv(1000) 
      if (data == "\quitting\\"): 
       return 
      data_recieved(self.sock.recv(1000)) 

#################################################################################### 
server = False 
uname = input("What's your username: ") 
print "Now for the technical info..." 
port = input("What port do I connect to ['any' if first]: ") 
#This is the first client. Let it get an available port 
if (port == "any"): 
    server = True 
    port = 9999 
    err = True 
    while err == True: 
     try: 
      sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
      sock.bind(('', port)) 
      err = False 
     except: 
      err = True 
     sock.close() 

    print "Bound to port #" + str(port) 
    print "Waiting for client..." 

    sock.listen(1) 
    (channel, info) = sock.accept() 
else: 
    #This is the client. Just bind it tho a predisposed port 
    host = input("What's the IP of the other client: ") 
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    sock.connect((host, int(port))) 

msg = "" 
if (server == True): 
    #Use the connection from accept 
    reader = socket_read(channel) 
else: 
    #Use the actual socket 
    reader = socket_read(sock) 
reader.start() 
while msg != 'quit': 
    #Get the message... 
    msg = uname + ": " + input("Message: ") 
    try: 
     #And send it 
     if (server == True): 
      #Use the connection from accept 
      channel.send(msg) 
     else: 
      #Use direct socket 
      sock.send(msg) 
    except: 
     break 
reader.join() 
channel.send("\quitting\\") 
sock.close() 

(我希望評論幫助)

總之,通過調用輸入的同時,並獲得對方套接字的消息時,我有一個小的同步化問題。我可以連接,但是當我收到消息時,它不會取消輸入語句。

換句話說,當我收到一個消息,它說這個

Message: user: I got a message 
#Flashing cursor here 

因此,它不會取消輸入語句。

此外,我只收到其他所有消息。

有什麼建議嗎?

+0

次要注意事項:「received」拼寫錯誤,您使用的「回調」不僅不是回調(它只是一個常規的函數調用),而是沒用的......用打印替換該調用,您將得到相同的結果。最後,input()是危險的,因爲它在用戶輸入上調用eval():相反,使用raw_input()會更安全,這可以做你可能認爲input()所做的事情。 – 2009-12-21 15:10:40

+0

感謝您的想法。我剛碰到一個逗號錯誤,這個錯誤是固定的。 – new123456 2009-12-21 15:34:27

回答

1

你在這裏所做的並不是一個同步問題,因爲它是一個演示/ UI問題。我建議讓你的生活更輕鬆,並選擇一些UI工具包(curses,wxPython,pyqt)來處理與用戶的交互。使用input()對於快速而骯髒的一次性代碼非常方便,但它並不十分複雜。

如果你這樣做,你會看到你根本不需要使用線程(就像往常一樣),你的問題就會像魔術一樣消失!

+0

感謝您的想法。但是,套接字是多線程的原因,而不是用戶交互。我需要監視輸入並立即發送輸出,而不是發送並等待回覆。 – new123456 2009-12-21 15:21:14

+0

你不應該使用套接字的線程。 例如,使用QT時,您可以在插座上有數據等待或用戶輸入端有信號。然後你可以處理它。事件循環負責所有其他事情。 你正在做的事情很容易出錯,就像你發現的那樣。 – drxzcl 2009-12-21 15:43:29

1

好吧,對於我自己的問題,很抱歉這麼快速回答,但使用線程時(至少在Linux的模型上),回調是神奇的。

總之,這樣做:

import socket 
import threading 

def msg_loop(socket): 
    msg = "" 
    if (server == True): 
     reader = socket_read(channel) 
    else: 
     reader = socket_read(sock) 
    reader.start() 
    while msg != 'quit': 
     msg = uname + " said : " + input("Message: ") 
     print "" 
     try: 
      if (server == True): 
       channel.send('null') 
       channel.send(msg) 
      else: 
       sock.send('null') 
       sock.send(msg) 
     except: 
      break 

def data_recieved(data, socket): 
    print "Hold on...\n\n" + data + "\n" 
    msg_loop(socket) 

class socket_read(threading.Thread): 
    sock = object 
    def __init__(self, sock): 
     threading.Thread.__init__(self) 
     self.sock = sock 
    def run(self): 
     while True: 
      data = self.sock.recv(1000) 
      if (data == "\quitting\\" or data == ''): 
       return 
      data_recieved(self.sock.recv(1000), self.sock) 

#################################################################################### 
server = False 
uname = str(input("What's your username: ")) 
print "Now for the technical stuff..." 
port = input("What port do I connect to ['any' if first]: ") 
if (port == "any"): 
    server = True 
    port = 9999 
    err = True 
    while err == True: 
     try: 
      sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
      sock.bind(('', port)) 
      err = False 
     except: 
      print "Socket #" + str(port) + " failed" 
      err = True 
      sock.close() 
      port -= 1 

    print "Bound to port #" + str(port) 
    print "Waiting for client..." 

    sock.listen(1) 
    (channel, info) = sock.accept() 
else: 
    host = input("What's the IP of the other client: ") 
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    sock.connect((host, int(port))) 

if (server == True): 
    msg_loop(channel) 
else: 
    msg_loop(sock) 

reader.join() 
channel.send("\quitting\\") 
sock.close() 

正如你所看到的,我加了消息循環作爲回調。

另請注意,我發送空值,以規避「其他」問題。

那,我在data_recieved的打印結束處使用換行符來禁用換行符。

(如果你喜歡的代碼,它不運行,以及在Windows上,這是因爲,很顯然,在那裏Python的線程模型不作爲instentaniously執行。嘗試在您的本地Linux框)

+1

這看起來不正確。 如果你一直在調用data_recieved和socket_read而不返回,你最終會崩潰。 – drxzcl 2009-12-21 15:41:36