2017-04-14 46 views
1

我正在寫一個簡單的消息程序(2個用戶),在終端上工作。這個多處理的python腳本有什麼問題?

對於它的實現,我決定創建2個進程,一個用於服務器(等待消息到達另一個用戶),另一個用於客戶端(只是將消息發送到另一個服務器進程用戶)

的事實是,當我運行它,我得到以下錯誤:

C:\>python message.py 

> Process Process-2: 
Traceback (most recent call last): 
File "C:\Python27\lib\multiprocessing\process.py", line 258, in_bootstrap 
self.run() 
File "C:\Python27\lib\multiprocessing\process.py", line 114, in run 
self._target(*self._args, **self._kwargs) 
File "C:\message.py", line 12, in send_messages 
message = raw_input('> ') 
EOFError 

Process Process-1: 
Traceback (most recent call last): 
File "C:\Python27\lib\multiprocessing\process.py", line 258, in 
_bootstrap 
self.run() 
File "C:\Python27\lib\multiprocessing\process.py", line 114, in run 
self._target(*self._args, **self._kwargs) 
File "C:\message.py", line 25, in receive_messages 
message = sc.recv(1024) 
error: [Errno 10054] An existing connection was forcibly closed by the 
remote host 

這是我的Python代碼

from multiprocessing import Process 
import socket 

direction = "localhost" 

global s 
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 
def send_messages(): 
    s.connect((direction, 5124)) 
    while True: 
     message = raw_input('> ') 
     s.send(message) 
     if message == 'close': 
      break 
    print 'Bye' 
    s.close() 

def receive_messages(): 
    s.bind(("localhost",5124)) 
    s.listen(2) 
    sc, addr = s.accept() 

    while True: 
     message = sc.recv(1024) 
     print message 
    sc.close() 
    s.close() 

if __name__ == '__main__': 

    p1 = Process(target = receive_messages) 
    p1.start() 
    p2 = Process(target = send_messages) 
    p2.start() 
    p1.join() 
    p2.join() 

注1:可以有由於從我的文本編輯器剪切並粘貼到計算器,會導致一些縮進錯誤。

注2:我在Windows 10

回答

1

See this question.

當你釀出Python中的線程,it closes stdin。您不能使用子流程來收集標準輸入。使用主線程來收集輸入,並將它們從主線程發佈到隊列中。有可能將stdin傳遞給另一個線程,但您可能需要在主線程中關閉它。

也許你可以通過使用fdopen()在子進程中重新打開stdin來解決這個問題。 See this answer

這裏是你的代碼的例子:

from multiprocessing import Process 
import socket 
import sys 
import os 

direction = "localhost" 

# I got this error 
# error: [Errno 106] Transport endpoint is already connected 
# when I run your code ,so I made some change 
# You can ignore it if everything is ok when your code run 

global s1 
s1 = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 

global s2 
s2 = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 

def send_messages(fileno): 
    s1.connect((direction, 5104)) 
    sys.stdin = os.fdopen(fileno) # open stdin in this process 
    while True: 
     message = '' 
     message = raw_input('> ') 
     s1.send(message) 
     if message == 'close': 
      break 

    print 'Bye' 
    s1.close() 

def receive_messages(): 
    s2.bind(("localhost",5104)) 
    s2.listen(2) 
    sc, addr = s2.accept() 

    while True: 
     message = sc.recv(1024) 
     if message == 'close': 
      print 'Bye!' 
      break 
     print message 

    sc.close() 
    s2.close() 

if __name__ == '__main__': 
    fn = sys.stdin.fileno() # get original file descriptor 
    p1 = Process(target = receive_messages) 
    p1.start() 
    p2 = Process(target = send_messages, args=(fn,)) 
    p2.start() 
    p1.join() 
    p2.join() 

我測試了它,和它的工作。

0

工作,你收到的錯誤基本上意味着你raw_input正在接收一個空的輸入。這種情況引發了EOFError,您可以在文檔的built-in-exceptions section中閱讀它。

我從來沒有嘗試過這樣的多處理之前,但我會想象這是你的問題所在。也許在進入多進程之前,確保你的邏輯在單個進程中按預期工作,但我仍然想嘗試啓動多個進程來接收用戶輸入會是一件令人頭疼的事情。

1

the documentation

Beware of replacing sys.stdin with a 「file like object」

multiprocessing originally unconditionally called:

os.close(sys.stdin.fileno()) 

in the multiprocessing.Process._bootstrap() method — this resulted in issues with processes-in-processes. This has been changed to:

sys.stdin.close() 
sys.stdin = open(os.open(os.devnull, os.O_RDONLY), closefd=False) 

Which solves the fundamental issue of processes colliding with each other resulting in a bad file descriptor error, but introduces a potential danger to applications which replace sys.stdin() with a 「file-like object」 with output buffering. This danger is that if multiple processes call close() on this file-like object, it could result in the same data being flushed to the object multiple times, resulting in corruption.

的底線是,你Process ES被關閉stdin除非你繼承他們和避免這樣做。

您可以考慮使用一個(資本P)進程來處理通信,然後該幹嘛輸入/輸出在原始(小寫)過程:

if __name__ == '__main__': 

    p1 = Process(target = receive_messages) 
    p1.start() 

    send_messages() 

    p1.join()