Python使用select模块实现Socket全双工异步通信详解
本文介绍如何利用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程序设计有所帮助。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









