使用Python实现多线程、多进程、异步IO的socket通信

打印 上一主题 下一主题

主题 791|帖子 791|积分 2375

多线程实现socket通信服务器端代码
  1. import socket
  2. import threading
  3. class MyServer(object):
  4.     def __init__(self):
  5.         # 初始化socket
  6.         self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  7.         # 设置服务器IP地址
  8.         host = '192.168.152.1'
  9.         # 设置服务器端口号
  10.         port = 4321
  11.         # 绑定IP地址和端口
  12.         self.server.bind((host, port))
  13.         # 设置最大监听数
  14.         self.server.listen(5)
  15.         # 设置一个字典,用来保存每一个客户端的连接和身份信息
  16.         self.socket_mapping = {}
  17.         # 设置接收的最大字节数
  18.         self.maxSize = 1024
  19.     def run(self):
  20.         while True:
  21.             socket, addr = self.server.accept()
  22.             # 发送信息,提示客户端已成功连接
  23.             socket.send('success!'.encode('utf-8'))
  24.             # 将客户端socket等信息存入字典
  25.             self.socket_mapping[socket] = addr
  26.             # 创建线程,负责获取键盘输入并发送给客户端
  27.             threading.Thread(target=self.send_to_client, args=(socket,)).start()
  28.             # 创建线程,负责接收客户端信息并转发给其他客户端
  29.             threading.Thread(target=self.recv_from_client, args=(socket,)).start()
  30.     def send_to_client(self, socket):
  31.         """
  32.         获取键盘输入并发送给客户端
  33.         :param socket:
  34.         :return:
  35.         """
  36.         while True:
  37.             info = input()
  38.             if info == "quit":
  39.                 socket.close()
  40.             for socket in self.socket_mapping.keys():
  41.                 socket.send(info.encode("utf-8"))
  42.     def recv_from_client(self, socket):
  43.         """
  44.         接收客户端信息并转发给其他客户端
  45.         :param socket:
  46.         :return:
  47.         """
  48.         while True:
  49.             recv_info = socket.recv(self.maxSize).decode('utf-8')
  50.             print('client{} say: '.format(self.socket_mapping[socket]), recv_info)
  51.             for i_socket in self.socket_mapping.keys():
  52.                 if i_socket != socket:
  53.                     i_socket.send(recv_info.encode("utf-8"))
  54. my_server = MyServer()
  55. my_server.run()
复制代码
多进程实现socket通信服务器端代码

存在的问题:在与客户端连通后,需要服务器先发送两条消息,之后才能正常通信。
  1. import os
  2. import socket
  3. import sys
  4. from multiprocessing import Process, Manager
  5. class MyServer(object):
  6.     def __init__(self):
  7.         # 初始化socket
  8.         self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  9.         # 设置服务器IP地址
  10.         host = '192.168.152.1'
  11.         # 设置服务器端口号
  12.         port = 4321
  13.         # 绑定IP地址和端口
  14.         self.server.bind((host, port))
  15.         # 设置最大监听数
  16.         self.server.listen(5)
  17.         # 设置一个字典,用来保存每一个客户端的连接和身份信息
  18.         self.socket_mapping = Manager().dict()
  19.         # 设置接收的最大字节数
  20.         self.maxSize = 1024
  21.         # 进程锁
  22.         self.share_lock = Manager().Lock()
  23.     def run(self):
  24.         fn = sys.stdin.fileno()
  25.         while True:
  26.             socket, addr = self.server.accept()
  27.             # 发送信息,提示客户端已成功连接
  28.             socket.send('success!'.encode('utf-8'))
  29.             # 将客户端socket等信息存入字典
  30.             self.modify_mapping(self.socket_mapping, addr, socket, self.share_lock)
  31.             # 创建进程,负责获取键盘输入并发送给客户端
  32.             Process(target=self.send_to_client, args=(addr, fn)).start()
  33.             # 创建进程,负责接收客户端信息并转发给其他客户端
  34.             Process(target=self.recv_from_client, args=(addr,)).start()
  35.     def send_to_client(self, addr, fn):
  36.         """
  37.         获取键盘输入并发送给客户端
  38.         :param addr:
  39.         :return:
  40.         """
  41.         sys.stdin = os.fdopen(fn)
  42.         while True:
  43.             info = sys.stdin.readline()
  44.             if info == "quit":
  45.                 self.socket_mapping[addr].close()
  46.             for socket in self.socket_mapping.values():
  47.                 socket.send(info.encode("utf-8"))
  48.     def recv_from_client(self, addr):
  49.         """
  50.         接收客户端信息并转发给其他客户端
  51.         :param addr:
  52.         :return:
  53.         """
  54.         while True:
  55.             recv_info = self.socket_mapping.get(addr).recv(self.maxSize).decode('utf-8')
  56.             print('client{} say: '.format(addr), recv_info)
  57.             for i_addr in self.socket_mapping.keys():
  58.                 if i_addr != addr:
  59.                     self.socket_mapping.get(i_addr).send(recv_info.encode("utf-8"))
  60.     @staticmethod
  61.     def modify_mapping(share_var, share_key, share_value, share_lock):
  62.         # 获取锁
  63.         share_lock.acquire()
  64.         # 修改数据
  65.         share_var[share_key] = share_value
  66.         # 释放锁
  67.         share_lock.release()
  68. if __name__ == "__main__":
  69.     my_server = MyServer()
  70.     my_server.run()
复制代码
异步IO实现socket通信服务器端代码

存在的问题:通信时需要相互发送几次消息后,各自才会收到之前的消息并打印。
  1. import socket
  2. import asyncio
  3. import select
  4. class MyServer(object):
  5.     def __init__(self):
  6.         # 初始化socket
  7.         self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  8.         # 设置服务器IP地址
  9.         host = '192.168.152.1'
  10.         # 设置服务器端口号
  11.         port = 4321
  12.         # 绑定IP地址和端口
  13.         self.server.bind((host, port))
  14.         # 设置最大监听数
  15.         self.server.listen(5)
  16.         # 设置一个字典,用来保存每一个客户端的连接和身份信息
  17.         self.socket_mapping = {self.server: None}  # 这里存入self.server是为了充当select.select参数
  18.         # 设置接收的最大字节数
  19.         self.maxSize = 1024
  20.         # 进入事件循环
  21.         self.loop = asyncio.get_event_loop()
  22.     def run(self):
  23.         while True:
  24.             # select监听请求对象
  25.             rret, _, _ = select.select(self.socket_mapping.keys(), [], [])
  26.             for r_socket in rret:
  27.                 if r_socket is self.server:
  28.                     socket, addr = r_socket.accept()
  29.                     # 发送信息,提示客户端已成功连接
  30.                     socket.send('success!'.encode('utf-8'))
  31.                     # 将客户端socket等信息存入字典
  32.                     self.socket_mapping[socket] = addr
  33.                 else:
  34.                     task = [self.send_to_client(r_socket), self.recv_from_client(r_socket)]
  35.                     self.loop.run_until_complete(asyncio.gather(*task))
  36.     async def send_to_client(self, socket):
  37.         """
  38.         获取键盘输入并发送给客户端
  39.         :param socket:
  40.         :return:
  41.         """
  42.         info = input()
  43.         if info == "quit":
  44.             socket.close()
  45.         for socket in self.socket_mapping.keys():
  46.             if socket != self.server:
  47.                 socket.send(info.encode("utf-8"))
  48.     async def recv_from_client(self, socket):
  49.         """
  50.         接收客户端信息并转发给其他客户端
  51.         :param socket:
  52.         :return:
  53.         """
  54.         recv_info = socket.recv(self.maxSize).decode('utf-8')
  55.         print('client{} say: '.format(self.socket_mapping[socket]), recv_info)
  56.         for i_socket in self.socket_mapping.keys():
  57.             if i_socket != socket and i_socket != self.server:
  58.                 i_socket.send(recv_info.encode("utf-8"))
  59. my_server = MyServer()
  60. my_server.run()
复制代码
客户端代码(使用多线程)
  1. import socket
  2. import threading
  3. class MyClient(object):
  4.     def __init__(self):
  5.         # 初始化socket
  6.         self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  7.         # 设置服务器IP地址
  8.         self.host = '192.168.152.1'
  9.         # 设置服务器端口号
  10.         self.port = 4321
  11.         # 设置接收的最大字节数
  12.         self.max_size = 1024
  13.     def run(self):
  14.         # 与服务器建立连接
  15.         self.client.connect((self.host, self.port))
  16.         # 创建线程,负责获取键盘输入并发送给服务器
  17.         threading.Thread(target=self.sned_to_server).start()
  18.         # 创建线程,接收服务器信息
  19.         threading.Thread(target=self.recv_from_server).start()
  20.     def sned_to_server(self):
  21.         """
  22.         获取键盘输入并发送给服务器
  23.         """
  24.         while True:
  25.             send_msg = input()
  26.             self.client.send(send_msg.encode('utf-8'))
  27.             if send_msg == 'quit':
  28.                 break
  29.         self.client.close()
  30.     def recv_from_server(self):
  31.         """
  32.         接收服务器信息
  33.         """
  34.         while True:
  35.             recv_info = self.client.recv(self.max_size).decode('utf-8')
  36.             print('server{} say: '.format((self.host, self.port)), recv_info)
  37. my_client = MyClient()
  38. my_client.run()
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

南七星之家

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表