Python:如何在recv中等待数据时关闭UDP套接字? [英] Python : How to close a UDP socket while is waiting for data in recv?

查看:61
本文介绍了Python:如何在recv中等待数据时关闭UDP套接字?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们在 python 中考虑这段代码:

let's consider this code in python:

import socket
import threading
import sys
import select


class UDPServer:
    def __init__(self):
        self.s=None
        self.t=None
    def start(self,port=8888):
        if not self.s:
            self.s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            self.s.bind(("",port))
            self.t=threading.Thread(target=self.run)
            self.t.start()
    def stop(self):
        if self.s:
            self.s.close()
            self.t.join()
            self.t=None
    def run(self):
        while True:
            try:
                #receive data
                data,addr=self.s.recvfrom(1024)
                self.onPacket(addr,data)
            except:
                break
        self.s=None
    def onPacket(self,addr,data):
        print addr,data


us=UDPServer()
while True:
    sys.stdout.write("UDP server> ")
    cmd=sys.stdin.readline()
    if cmd=="start\n":
        print "starting server..."
        us.start(8888)
        print "done"
    elif cmd=="stop\n":
        print "stopping server..."
        us.stop()
        print "done"
    elif cmd=="quit\n":
        print "Quitting ..."
        us.stop()
        break;

print "bye bye"

它运行一个交互式 shell,我可以用它启动和停止 UDP 服务器.服务器是通过一个类来实现的,该类启动一个线程,其中在 try/except 块内有一个无限循环的 recv/onPacket 回调,它应该检测错误和退出从循环.我期望的是,当我在 shell 上键入stop"时,套接字将关闭,并且由于文件描述符无效,recvfrom 函数会引发异常.相反,即使在 close 调用之后,recvfrom 似乎仍然阻塞等待数据的线程.为什么会有这种奇怪的行为?我一直使用这个模式在 C++ 和 JAVA 中实现一个 UDP 服务器,它总是有效.

It runs an interactive shell with which I can start and stop an UDP server. The server is implemented through a class which launches a thread in which there's a infinite loop of recv/onPacket callback inside a try/except block which should detect the error and the exits from the loop. What I expect is that when I type "stop" on the shell the socket is closed and an exception is raised by the recvfrom function because of the invalidation of the file descriptor. Instead, it seems that recvfrom still to block the thread waiting for data even after the close call. Why this strange behavior ? I've always used this patter to implements an UDP server in C++ and JAVA and it always worked.

我也尝试过使用select"将带有套接字的列表传递给 xread 参数,以便从 xread 参数中获取文件描述符中断事件strong>select 而不是来自 recvfrom,但 select 似乎对 close 也不明智".

I've tried also with a "select" passing a list with the socket to the xread argument, in order to get an event of file descriptor disruption from select instead that from recvfrom, but select seems to be "insensible" to the close too.

我需要一个独特的代码,在使用 python 2.5 - 2.6 的 Linux 和 Windows 上保持相同的行为.

I need to have a unique code which maintain the same behavior on Linux and Windows with python 2.5 - 2.6.

谢谢.

推荐答案

通常的解决方案是让管道告诉工作线程何时死亡.

The usual solution is to have a pipe tell the worker thread when to die.

  1. 使用 os.pipe 创建管道.这为您提供了一个在同一个程序中具有读写端的套接字.它返回原始文件描述符,您可以按原样使用(os.reados.write)或使用 os.fdopen<转换为 Python 文件对象/code>.

  1. Create a pipe using os.pipe. This gives you a socket with both the reading and writing ends in the same program. It returns raw file descriptors, which you can use as-is (os.read and os.write) or turn into Python file objects using os.fdopen.

工作线程使用select.select 等待 网络套接字和管道的读取端.当管道变得可读时,工作线程会清理并退出.不要读取数据,忽略它:它的到来就是消息.

The worker thread waits on both the network socket and the read end of the pipe using select.select. When the pipe becomes readable, the worker thread cleans up and exits. Don't read the data, ignore it: its arrival is the message.

当主线程想要杀死工作线程时,它会向管道的写端写入一个字节(任何值).然后主线程加入工作线程,然后关闭管道(记得两端都关闭).

When the master thread wants to kill the worker, it writes a byte (any value) to the write end of the pipe. The master thread then joins the worker thread, then closes the pipe (remember to close both ends).

附言在多线程程序中关闭正在使用的套接字是一个坏主意.Linux close(2) 联机帮助页说:

P.S. Closing an in-use socket is a bad idea in a multi-threaded program. The Linux close(2) manpage says:

关闭文件描述符可能是不明智的,因为它们可能被同一进程中的其他线程中的系统调用使用.由于文件描述符可能会被重复使用,因此存在一些可能导致意外副作用的模糊竞争条件.

It is probably unwise to close file descriptors while they may be in use by system calls in other threads in the same process. Since a file descriptor may be re-used, there are some obscure race conditions that may cause unintended side effects.

幸运的是,您的第一种方法没有奏效!

So it's lucky your first approach did not work!

这篇关于Python:如何在recv中等待数据时关闭UDP套接字?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆