Python使用select模块实现Socket全双工异步通信详解

Dylan
Dylan
发布时间:2026-10-13 | 6人浏览过
原创

本文介绍如何利用Python的select模块实现Socket全双工异步通信,解决传统TCP通信中收发不能并行的问题。通过管理多个套接字连接,代码示例展示了服务器与客户端的一对一聊天功能,并探讨了基于服务器中转的多对多通信思路。

本文通过一个具体实例,展示如何在Python网络编程中利用select模块实现Socket的全双工异步通信功能。内容旨在为读者提供参考和借鉴。

在之前的《Python网络编程之TCP套接字简单用法》一文中,我们实现了基础的TCP客户端与服务器通信。然而,该方案存在功能局限,无法同时发送和接收消息。

接下来,我们将借助select模块来实现全双工通信,即允许随时接收和发送信息。虽然多线程也能达成类似效果,但这部分将在后续讨论。

那么,select究竟是什么?

select主要用于单线程网络服务器程序中,以管理多个套接字连接。

select函数的原型为(rlist, wlist, xlist[, timeout])。其中,rlist代表等待读取的对象列表,wlist代表等待写入的对象列表,xlist代表等待异常的对象列表。最后一个参数timeout是可选的,用于指定等待时间,单位为秒。

select()方法的返回值是一个包含准备好对象的三元组。如果在指定的timeout时间内没有任何对象准备好,该方法将返回空列表。

该机制通过轮询方式来实现异步通信效果。

在下面的程序示例中,主要支持一对一通信场景。当通信双方中的任意一方发送字符串'88'时,即表示结束当前的通信会话。

下面我们来查看具体的代码实现。

首先是服务器端的代码实现。

#!/usr/bin/python
'test TCP server'
from socket import *
from time import ctime
import select
import sys
HOST = ''
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST, PORT)
tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)
input = [tcpSerSock, sys.stdin]   #input是一个列表,初始有欢迎套接字以及标准输入
while True:
  print 'waiting for connection...'
  tcpCliSock, addr = tcpSerSock.accept()
  print '...connected from:',addr
  input.append(tcpCliSock)  #将服务套接字加入到input列表中
  while True:
    readyInput,readyOutput,readyException = select.select(input,[],[]) #从input中选择,轮流处理client的请求连接(tcpSerSock),client发送来的消息(tcpCliSock),及服务器端的发送消息(stdin)
    for indata in readyInput:
      if indata==tcpCliSock:  #处理client发送来的消息
        data = tcpCliSock.recv(BUFSIZ)
        print data
        if data=='88':
          input.remove(tcpCliSock)
          break
      else:       #处理服务器端的发送消息
        data = raw_input('>')
        if data=='88':
          tcpCliSock.send('%s' %(data))
          input.remove(tcpCliSock)
          break
        tcpCliSock.send('[%s] %s' %(ctime(), data))
    if data=='88':
      break
  tcpCliSock.close()
tcpSerSock.close()

以下是客户端的代码,其结构与服务器非常相似,区别在于客户端不需要处理来自其他客户端的请求信息。

#!/usr/bin/python
'test tcp client'
from socket import *
from time import ctime
import select
import sys
HOST = 'localhost'
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST, PORT)
tcpCliSock = socket(AF_INET, SOCK_STREAM)
tcpCliSock.connect(ADDR)
input = [tcpCliSock,sys.stdin]
while True:
  readyInput,readyOutput,readyException = select.select(input,[],[])
  for indata in readyInput:
    if indata==tcpCliSock:
      data = tcpCliSock.recv(BUFSIZ)
      print data
      if data=='88':
        break
    else:
      data = raw_input('>')
      if data=='88':
        tcpCliSock.send('%s' %(data))
        break
      tcpCliSock.send('[%s] %s' %(ctime(), data))
  if data=='88':
    break
tcpCliSock.close()

至此,我们已经成功实现了一对一的全双工聊天通信功能。

接下来,我们需要思考如何进一步实现多对多通信。

我们知道,一个服务器可以同时为多个客户端提供服务,即服务器与客户端之间是一对多的关系。那么,我们可以尝试利用服务器作为中间节点来转发信息,从而实现多对多通信吗?

举例来说,如果用户A想要与用户B通信,A可以将信息发送给服务器,再由服务器转发给B。按照这一思路编写代码,理论上可以完成多对多通信的实现,有兴趣的读者可以尝试实践。

更多关于Python的相关技巧,您可以查阅本站的以下专题:《Python Socket编程技巧总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》以及《Python文件与目录操作技巧汇总》。

希望本文所述内容能对您的Python程序设计有所帮助。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表