关于在Python中使用Jython时运行接收套接字的问题

2 投票
2 回答
1160 浏览
提问于 2025-04-15 20:57

我对Python和网络编程了解不多。目前,我正在尝试实现一个简单的应用程序,这个程序可以接收用户发送的文本消息,从谷歌搜索API获取一些信息,然后通过文本消息将结果返回给用户。这个应用程序会持续监听用户的消息,并立即回复。

我该如何获取用户发送的短消息呢?这是一个名为“飞信”的程序,来自中国的移动运营商。客户端的飞信就像一个即时通讯工具,可以向其他使用手机发送/接收短信的人发送和接收消息。

我正在使用一个开源的Python程序,它模拟了飞信程序。因此,基本上我可以用这个Python程序与其他通过短信使用手机的人进行交流。

我的核心程序是基于Java的,所以我需要把这个Python程序放到Java环境中。我正在使用Jython,现在我可以通过几行Java代码向用户发送消息。

但真正的问题是如何通过短信接收用户的消息。在Python代码中,会创建一个新线程来持续监听用户的消息。在Python中这样做应该没问题,但当我在Jython中运行类似的过程时,就出现了以下异常:

Exception in thread Thread:Traceback (most recent call last):
File "D:\jython2.5.1\Lib\threading.py", line 178, in _Thread__bootstrap
   self.run()
File "<iostream>", line 1389, in run
File "<iostream>", line 1207, in receive
File "<iostream>", line 1207, in receive
File "<iostream>", line 150, in recv
File "D:\jython2.5.1\Lib\select.py", line 223, in native_select
  pobj.register(fd, POLLIN)
File "D:\jython2.5.1\Lib\select.py", line 104, in register
  raise _map_exception(jlx)
error: (20000, 'socket must be in non-blocking mode')

Python代码中的第150行如下:

def recv(self,timeout=False):
    if self.login_type == "HTTP":
        time.sleep(10)
        return self.get_offline_msg()
        pass
    else:
        if timeout:
            infd,outfd,errfd = select([self.__sock,],[],[],timeout)//<---line 150 here
        else:
            infd,outfd,errfd = select([self.__sock,],[],[])

        if len(infd) != 0:
            ret = self.__tcp_recv()

            num = len(ret)
            d_print(('num',),locals())
            if num == 0:
                return ret
            if num == 1:
                return ret[0]
            for r in ret:
                self.queue.put(r)
                d_print(('r',),locals())

            if not self.queue.empty():
                return self.queue.get()

        else:
            return "TimeOut"

因为我对Python不太熟悉,尤其是关于socket的部分,而且对Jython的使用也很陌生,所以我真的需要你的帮助,或者只是一些建议或解释。

非常感谢你!

2 个回答

1

这个错误提示你尝试在一个默认情况下会阻塞等待输入的套接字上调用了select。要让它变成非阻塞的方式,你需要找到self.__sock是在哪里创建的,然后在它上面调用socket.setblocking(0)

理论上,你可以在调用select之前在recv中调用setblocking,但这样会让读的人感到困惑。因为这些都是直接调用底层套接字的操作,所以这其实不是一个纯粹的Python问题,而是关于你所使用的平台上socket系统调用的工作原理。

2

在jython的选择模块文档页面上提到,只有非阻塞模式的套接字才能在jython中进行多路复用。与此不同的是,在cpython中,套接字可以是阻塞的,也可以是非阻塞的。

http://wiki.python.org/jython/SelectModule#Onlysocketsinnon-blockingmodecanbemultiplexed

这是Java的一个限制,jython无法改变这一点。

在jython的选择模块中,有一个专门为这种情况设计的函数,叫做cpython_compatible_select函数。

你在上面的代码中没有显示导入选择模块,但根据我看到的,你应该是这样导入的:

from select import select

如果你把这个导入改成:

from select import cpython_compatible_select as select

那么一切应该就能正常工作了。

最后,请确保阅读选择模块文档页面上的“警告”部分。

撰写回答