Python socket在mulitprocessing、threading、asyncio中的实现

前言

本文主要是记录下三种实现异步非阻塞socket网络编程的方法,一来加深印象,二来以便日后用到时对其用法生疏。不讨论三种实现方法的优略。

简介 备注
mulitprocessing 多进程
threading 多线程
asyncio 协程

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import socket

sk = socket.socket()
sk.connect(('127.0.0.1',4396))
print(sk.recv(1024).decode())
while 1:
inp = input('>')
sk.send(inp.encode())
if inp == 'exit':
break
msg = sk.recv(1024).decode()
print('来自服务端的信息:%s' %(msg))

sk.close()

mulitprocessing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from multiprocessing import Process
import socket

def link_addr(coon,addr):
coon.send('欢迎使用socket'.encode())
while 1:
msg = coon.recv(1024).decode()
if msg == 'exit':
break
print('来自%s的信息:%s'%(addr,msg))
inp = 'ok'
coon.send(inp.encode())
coon.close()
if __name__ == '__main__':
sk = socket.socket()
ip_port = ('127.0.0.1',4396)
sk.bind(ip_port)
sk.listen()
print('多进程服务端已启动,请等待连接…………')
while 1:
coon, addr = sk.accept()
Process(target=link_addr, args=(coon, addr)).start()

sk.close()

threading

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import socket
import threading

# sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

def link_addr(coon,addr):
coon.send('欢迎使用socket'.encode())
while 1:
msg = coon.recv(1024).decode()
if msg == 'exit':
break
print('来自%s的信息:%s'%(addr,msg))
inp = 'ok'
coon.send(inp.encode())
coon.close()
if __name__ == '__main__':
sk = socket.socket()
ip_port = ('127.0.0.1',4396)
sk.bind(ip_port)
sk.listen()
print('多线程服务端已启动,请等待连接…………')
while 1:
coon, addr = sk.accept()
threading.Thread(target=link_addr, args=(coon, addr)).start()

sk.close()

socketserver

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import socketserver

class Mysock(socketserver.BaseRequestHandler):
'''
这里必须要继承socketserver.BaseRequestHandler这个类
'''

def handle(self):
'''
这里必须定义handle方法,而且一般在这里加循环,handle结束就意味着这个连接的结束
:return: None
'''
conn = self.request # 所有的请求信息都在self,request里头
conn.send('欢迎使用多线程socket——类版本'.encode())
while 1:
msg = conn.recv(1024).decode()
if msg == 'exit':
break
print('收到来自%s的信息:%s' %(self.client_address,msg))
conn.send('已收到您的消息'.encode())

if __name__ == '__main__':
# 创建一个多线程的TCP服务端
sk = socketserver.ThreadingTCPServer(('127.0.0.1', 4396), Mysock)
# 启动服务端并保持运行状态
sk.serve_forever()

asyncio

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import asyncio
# 服务端
# 推荐写法或标准写法
# 不需要用到原始socket

async def handler_client(reader, writer):#
'''
这个协程是要传给asyncio.start_server的
这里要接收两个对象,reader 和 writer(对应接受消息和发送消息,可以抽象的理解成socket里头的conn.recv和conn.send)
:param reader: asyncio.StreamReader
:param writer: asyncio.StreamWriter
:return: None
:Links: https://docs.python.org/3/library/asyncio-stream.html,
https://stackoverflow.com/questions/48506460/python-simple-socket-client-server-using-asyncio
'''
msg = None
addr = writer.get_extra_info('peername')
writer.write('欢迎使用asyncio+socket服务端!'.encode()) # 发送数据(必须配合drain使用)
await writer.drain() # 等待 直到适合继续写入流为止(官方docx这么写..)
while msg != 'exit':
msg = (await reader.read(1024)).decode('utf8')
print(f'来自{addr!r}的信息:{msg!r}')
writer.write('ok!'.encode())
await writer.drain()
writer.close()
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.create_task(asyncio.start_server(handler_client, '127.0.0.1', 4396, loop=loop))
print('Server running...')
loop.run_forever()

socket 写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import asyncio
import socket

# 服务端

# 非标准写法
async def handler_client(conn):
msg = None
await loop.sock_sendall(conn, '欢迎使用asyncio+socke'.encode()) # 发送
while msg != 'exit':
msg = (await loop.sock_recv(conn, 1024)).decode('utf8') # 接受信息
print('来自%s的信息:%s' % (str(conn), msg)) # 打印信息
await loop.sock_sendall(conn, 'ok!'.encode()) # 发送信息
conn.close()

async def main():
while 1:
conn, addr = await loop.sock_accept(sk) # 传入一个socket对象
loop.create_task(handler_client(conn)) # 将创建一个连接对象任务,并丢进事件循环

if __name__ == '__main__':
sk = socket.socket()
sk.bind(('127.0.0.1', 4396))
sk.listen(20)
sk.setblocking(False) # 需要将socket设置成非阻塞模式
print('listen run...')
loop = asyncio.get_event_loop()
loop.run_until_complete(main())

交个朋友
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

吹吹牛吗?

微信