【问题标题】:Window socket programming with Python使用 Python 进行窗口套接字编程
【发布时间】:2012-03-15 07:55:22
【问题描述】:

我正在尝试使用 Python 实现 Window 套接字。

到目前为止,所有问题都已使用 ctypes.windll.ws2_32 和 pywin32 lib 解决。

但是,我一直无法找到如何将以下 C++ 代码翻译成 Python,我想知道是否有人愿意提供帮助:

LRESULT WINAPI AsyncSocketProc(
                           __in  HWND hwnd,
                           __in  UINT uMsg,
                           __in  WPARAM wParam,
                           __in  LPARAM lParam
                          )
switch(uMsg) {
    case WM_CREATE: 
        //...
    case WM_SOCKET: {# this is basically an int constant
        switch(WSAGETSELECTEVENT(lParam)){
              case FD_ACCEPT:
                  //accepting new conn
              case FD_READ:
                  //receiving data 
        }
    }
}

在上面的代码中,我找不到 WSAGETSELECTEVENT 的 Python 等效项。

对于 FD_ACCEPT、FD_READ,我可以在 win32file 包(pywin32 lib)中找到它们

最后,我尝试实现这个窗口套接字编程的原因是窗口套接字服务器的 C++ 版本(上图)对于我的应用程序是非阻塞的,但 Python 的内置 select.select 是阻塞的.所以我想看看我是否可以将 C++ 版本移植到 Python 并查看它是否有效。

编辑: 我想澄清一下,套接字服务器作为现有 C++ 程序的“插件”工作,它不支持线程

套接字服务器需要(无限期地)等待客户端连接,因此它需要不断地监听。 因此,使用普通的 Python 套接字或 select.select 将需要一个 while 循环(否则它如何充当服务器不断侦听事件?请纠正我我错了),这将阻止主程序。

不知何故,使用上面的Window Socket服务器回调,主程序没有被阻塞。这是我尝试将其移植到 Python 的主要原因。

套接字服务器最好用 Python 编写,因为服务器需要的许多相关库都是用 Python 编写的。

非常感谢。

【问题讨论】:

  • 如果你对select.select使用零超时,那么它不会阻塞。
  • @JoachimPileborg 谢谢:这将使选择不会阻塞。但是,出于我的目的,服务器仍然会阻塞主程序,因为我们需要在 select.select 之外有一个 while 循环。我已经编辑了我的问题以澄清我的目的。谢谢。

标签: python sockets window ctypes pywin32


【解决方案1】:

改为查看socket module。它已经包含了在不使用 win32 API 的情况下使用套接字所需的所有代码。

[编辑] 您可以编写可以处理多个连接的多线程代码。只需接受连接,然后启动一个新线程,给它连接,让它在while 1: data = conn.recv(1024) ... 循环中读取数据。

也就是说,Python 也有一个模块:SocketServer

[EDIT2]你说

套接字服务器作为不支持线程的现有程序的“插件”。

用这么少的信息来帮助有点困难,但是这样想:

您可以在新线程中运行套接字服务器循环。此代码与您的应用程序的其余部分隔离,因此其他代码是否使用/支持线程并不重要。这解决了您的“无限循环”问题。

现在这个套接字服务器循环将从客户端获取连接。我的猜测是客户端会从应用程序的其余部分调用方法,而在这里,事情变得很棘手。

您需要一种方法来同步这些调用。在其他地方(如所有 UI 框架),只有一个线程运行任何 UI 调用(绘制东西、创建 UI、响应用户输入)。

但如果我理解正确,那么您实际上可以修改现有应用程序的“主循环”并让它做更多的事情(比如监听新连接)。如果你能做到这一点,那么就有了出路:

如上所述为套接字服务器创建一个新线程。当服务器获得连接时,产生一个与客户端对话的新线程。当客户端发送命令时,创建“工作对象”(参见command pattern)并将它们放入queue

在主循环中,您可以查看队列。如果里面有东西,弹出工作对象并调用它的run() 方法。

【讨论】:

  • 谢谢。 socket 模块确实不错,但它阻塞了主程序,似乎不支持线程。 while 1: data = conn.recv(1024) ... while 1 阻塞了我的主程序。
  • 如果您不想阻塞,请将套接字设置为非阻塞。当然,不要使用 while 这样的循环。
  • 您可以使用常规套接字方法进行阻塞和非阻塞读/写。如果要使用阻塞读取,则必须使用多线程/进程,如果要使用非阻塞读取,则需要使用 selec.select 其他一些套接字轮询工具。
  • @DavidSchwartz:谢谢。您能否澄清一下如何避免服务器的while循环。我认为我们需要它循环才能持续监听事件?
  • @JoãoPinto。谢谢您的建议。 select.select 可以是非阻塞的 timeout=0 但我仍然有外部 while 循环的问题,我无法摆脱它,因为它是一个服务器。我在问题中再次澄清了我的情况。谢谢!
【解决方案2】:

您不需要或不想移植此代码。此代码特定于 WIN32 API 如何通知本机代码套接字操作已完成。它不适用于 Python。

python 中的等价物大致是将“accepting new conn”代码粘贴到您的 python 代码接受新连接的任何位置。并将“接收数据”代码粘贴到您的 python 代码接收数据的任何位置。

您也可以使用select,但请记住,语义有点与异步套接字相反。使用异步套接字,您可以随时启动操作,并在操作完成时收到回调。使用“选择”,它会告诉您何时执行操作以使其立即完成。

【讨论】:

  • 谢谢。根据您的解释,看来 Window 的 Async 套接字是我真正需要的。有没有办法在 Python 中实现它?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多