简体   繁体   English

Python 接受的套接字连接未关闭

[英]Python accepted socket connection not closing

I've written a Pi Hardware Interface Server (phis) that uses http protocol to control the hardware connected to my Raspberry Pi (relays, analog measurements, etc).我编写了一个 Pi 硬件接口服务器 (phis),它使用 http 协议来控制连接到我的 Raspberry Pi 的硬件(继电器、模拟测量等)。 It processes simple requests and responds with plain text.它处理简单的请求并以纯文本响应。 It has been working flawlessly for years and I have written extensive browser-based interfaces to the system.多年来它一直在完美运行,我已经为系统编写了广泛的基于浏览器的界面。 Here's the basic structure:这是基本结构:

listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_socket.bind((HOST, PORT))
listen_socket.listen(1)

read_list = [listen_socket]

while True:
    readable, writeable, errored = select.select(read_list,[], [], 2)
    if len(readable) == 0: # select timed out
        continue

    client_connection, client_address = listen_socket.accept()
    try:
        request = client_connection.recv(1024)
    except Exception:
        print "Exception trying to recv, %s" % time.strftime(date_format)
        sys.exc_clear()
        client_connection.close()
        continue

    words = request.split()

    http_response = """\
HTTP/1.1 200 OK
"""
    try:
        client_connection.sendall(http_response)
    except Exception:
        print "Exception trying to send 1, %s" % time.strftime(date_format)
        sys.exc_clear()
        client_connection.close()
        continue

    http_response = """\
Content-Type: text/plain; charset=utf-8

"""

# perform some action and add text to the http_response (like current CPU temperature, etc)

    try:
        client_connection.sendall(http_response)
    except Exception:
        # log the error, then...
        sys.exc_clear()
        client_connection.close()
        continue

    client_connection.close()

    if words[1] == '/exit':
        sys.exit(0)

The problem occurs when the command is to start mjpg_streamer.当命令是启动 mjpg_streamer 时会出现问题。 The stream starts just fine, the response is sent and I can make more connections and issue new commands, but the client_connection.close() never actually closes the connection and the browser just sits there waiting for more stuff that never comes. stream 启动得很好,响应已发送,我可以建立更多连接并发出新命令,但 client_connection.close() 从未真正关闭连接,浏览器只是坐在那里等待更多永远不会出现的东西。 The phis is still accepting new connections and servicing those, but if I exit the server with the request "http://pi:4000/exit", it does so cleanly, but it wont start again (socket in use) unless I first issue the request to stop mjpg_streams (which also works just fine). phis 仍在接受新连接并为这些连接提供服务,但如果我使用请求“http://pi:4000/exit”退出服务器,它会干净利落地执行,但除非我先启动,否则它不会再次启动(正在使用套接字)发出停止 mjpg_streams 的请求(也可以正常工作)。

mjpg_streamer already starts in (what seems to be) a daemonized background mode, but in my attempts to get this working, I have issued the command to start it in every python "start your background child and leave it running" method I could find (os.system(), subprocess.Popen(), os.fork() and os.fork() twice with os.setsid() in between). mjpg_streamer 已经在(似乎是)守护进程后台模式下启动,但在我尝试让它工作时,我已经发出命令在每个 python“启动你的背景孩子并让它运行”方法中启动它我能找到( os.system()、subprocess.Popen()、os.fork() 和 os.fork() 两次,os.setsid() 介于两者之间)。 Nothing worked.没有任何效果。

If it matters, I'm actually calling a perl script from the phis that starts mjpg_steamer with command line arguments based on arguments passed to the perl script. If it matters, I'm actually calling a perl script from the phis that starts mjpg_steamer with command line arguments based on arguments passed to the perl script.

I have googled much on this and found others with connections that would not close, but not with connections that close perfectly unless some background socket-based app is spawned while the connection is active.我对此进行了很多搜索,发现其他连接不会关闭,但连接不会完美关闭,除非在连接处于活动状态时生成了一些基于套接字的后台应用程序。 Anyone have any idea what's wrong?有人知道出了什么问题吗?

Found the answer in this post ("Duh" moment the instant I saw it!)这篇文章中找到了答案(我看到它的那一刻“Duh”!)

I had forgotten to close the connected and listening sockets in the forked child, which were inherited by the spawned daemon and stayed open as long as it runs.我忘记关闭分叉子进程中连接和监听的 sockets,这些子进程由衍生的守护进程继承,只要它运行就保持打开状态。 Here's the code I'm using to spawn a process that will be left running (daemonized):这是我用来生成将继续运行(守护进程)的进程的代码:

def spawnDaemon(syscmd):
    # do the UNIX double-fork magic, see Stevens' "Advanced 
    # Programming in the UNIX Environment" for details (ISBN 0201563177)
    try: 
        pid = os.fork() 
        if pid > 0:
            # parent process, wait for first child, then return and keep running
            os.wait()
            #print "first parent returning"
            return
    except OSError, e:
        print >>sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror) 
        sys.exit(1)

    # close the copy of the socket the request came in on
    client_connection.close()

    # close the copy of the server's main listening socket
    listen_socket.close()

    # change process group to detach the child (mjpeg_streamer) from the parent phis
    os.setsid()

    # do second fork
    #print "trying second fork"
    try: 
        pid = os.fork() 
        if pid > 0:
            # exit from second parent
            #print "second parent exiting"
            sys.exit(0) 
    except OSError, e: 
        print >>sys.stderr, "fork #2 failed: %d (%s)" % (e.errno, e.strerror) 
        sys.exit(1)

    # execute the command
    os.system(syscmd)

    # all done, exit 2nd child
    #print "exiting after executing syscmd"
    sys.exit(0)
# spawnDaemon()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM