这个多处理python脚本有什么问题?

时间:2017-04-14 02:40:33

标签: python networking multiprocessing

我正在编写一个适用于终端的简单消息程序(适用于2个用户)。

为了实现,我决定创建2个进程,一个用于服务器(等待消息从另一个用户到达),另一个用于客户端(只是将消息发送到另一个用户的服务器进程) )

事实是,当我运行它时,我收到以下错误:

//main.cpp
#include "mainwindow.h"
#include <QApplication>
#include "myserver.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    MyServer *Server = new MyServer;

    MainWindow w(Server);
    w.show();

    return a.exec();
}

这是我的Python代码

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

注意1:由于从文本编辑器到stackoverflow的剪切和粘贴,可能会出现一些缩进错误。

注意2:我正在使用Windows 10

3 个答案:

答案 0 :(得分:2)

来自the documentation

  

小心用“像对象这样的文件”替换sys.stdin

     

最初无条件地称为多处理:

os.close(sys.stdin.fileno())
  multiprocessing.Process._bootstrap()方法中的

- 这导致了进程中的进程问题。这已改为:

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

这解决了进程相互冲突导致文件描述符错误的基本问题,但是对于将sys.stdin()替换为具有输出缓冲的“类文件对象”的应用程序会带来潜在的危险。这种危险是,如果多个进程在此类文件对象上调用close(),则可能导致相同的数据被多次刷新到对象,从而导致损坏。

底线是你的Process es正在关闭stdin,除非你将它们分类并避免这样做。

您可以考虑使用一个(capital-P)流程处理通信,然后在原始(小写)流程中执行输入/输出:

if __name__ == '__main__':

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

   send_messages()

   p1.join()

答案 1 :(得分:1)

See this question.

当您在Python中生成线程时,it closes stdin。您不能使用子流程来收集标准输入。使用主线程来收集输入,并从主线程将它们发布到Queue。可以将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()

我测试了它,它起作用了。

答案 2 :(得分:0)

您收到的错误基本上意味着您的raw_input正在接收空输入。这种情况引发了EOFError,您可以在文档的built-in-exceptions section中阅读它。

我之前从未尝试使用多处理这样的东西,但我想这就是你的问题所在。也许确保你的逻辑在转移到多进程之前在单个进程中按预期工作,但我仍然觉得尝试启动多个进程来接收用户输入将是一件令人头疼的问题。