多线程实现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()

使用Python实现多线程、多进程、异步IO的socket通信的更多相关文章

  1. Python学习——多线程,异步IO,生成器,协程

    Python的语法是简洁的,也是难理解的. 比如yield关键字: def fun(): for i in range(5): print('test') x = yield i print('goo ...

  2. 多线程/多进程/异步IO

    SOCK_STREAM :TCPSOCK_Dgram :UDP family=AF_INET: 服务器之间的通信AF_INET6: 服务器之间的通信AF_UNIX: Unix不同进程间的通信 永远遵循 ...

  3. Python之路,Day10 - 异步IO\数据库\队列\缓存

    Python之路,Day9 - 异步IO\数据库\队列\缓存   本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitM ...

  4. Day10 - Python协程、异步IO、redis缓存、rabbitMQ队列

    Python之路,Day9 - 异步IO\数据库\队列\缓存   本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitM ...

  5. 从Nginx的Web请求处理机制中剖析多进程、多线程、异步IO

    Nginx服务器web请求处理机制 从设计架构来说,Nginx服务器是与众不同的.不同之处一方面体现在它的模块化设计,另一方面,也是最重要的一方面,体现在它对客户端请求的处理机制上. Web服务器和客 ...

  6. python中同步、多线程、异步IO、多线程对IO密集型的影响

    目录 1.常见并发类型 2.同步版本 3.多线程 4.异步IO 5.多进程 6.总结 1.常见并发类型 I/ O密集型: 蓝色框表示程序执行工作的时间,红色框表示等待I/O操作完成的时间.此图没有按比 ...

  7. Python协程、异步IO

    本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitMQ队列 Redis\Memcached缓存 Paramiko SS ...

  8. Python高级编程和异步IO并发编程

    第1章 课程简介介绍如何配置系统的开发环境以及如何加入github私人仓库获取最新源码. 1-1 导学 试看 1-2 开发环境配置 1-3 资源获取方式第2章 python中一切皆对象本章节首先对比静 ...

  9. 【Python之路】异步IO

    线程:CPU基本执行单元,可以与同属一个进程的其他线程共享资源,线程是属于进程的. 进程:资源单元,进程一般由程序.数据集.进程控制块三部分组成.一个进程默认有一个主线程, GIL:用于在进程中对所有 ...

  10. python 多协程异步IO爬取网页加速3倍。

    from urllib import request import gevent,time from gevent import monkey#该模块让当前程序所有io操作单独标记,进行异步操作. m ...

随机推荐

  1. (数据科学学习手札142)dill:Python中增强版的pickle

    本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 大家好我是费老师,相信不少读者朋友们都在Pyth ...

  2. 使用J2EE 登录实例开发

    我们先了解下Servlet的生命周期 Servlet部署在容器里,其生命周期由容器管理. 概括为以下几个阶段: 1)容器加载Servlet类. 当第一次有Web客户请求Servlet服务或当Web服务 ...

  3. Python数据科学手册-Numpy的结构化数组

    结构化数组 和 记录数组 为复合的.异构的数据提供了非常有效的存储 (一般使用pandas 的 DataFrame来实现) 传入的dtpye 使用 Numpy数据类型 Character Descri ...

  4. Grafana Loki 架构

    转载自:https://mp.weixin.qq.com/s?__biz=MzU4MjQ0MTU4Ng==&mid=2247492186&idx=2&sn=a06954384a ...

  5. img和div之间有间隙的原因及解决方法

    div 中 存在 img标签,由于img标签的 display:inline-block 属性. #####display:inline-block布局的元素在chrome下会出现几像素的间隙,原因是 ...

  6. OSF--网络类型

    ABR:区域边界路由器ASBR:自治区域系统边界路由器区域部署原则:    存在vlink本地网络一定是有问题的.他只是作为一种过度技术,在vlink里无法实现认证! 配置:   [r2-ospf-a ...

  7. PAT乙级 1024 科学计数法

    思路 1.尝试失败:一开始想打算把结果直接存在一个字符串中,后来发现当指数大于0的时候还需要分别考虑两种情况,工程量巨大,尝试失败,于是借鉴了其他大佬思路,写出了ac代码 2.ac思路:首先取指数的绝 ...

  8. 简书是如何把用户wo逼疯的

    趁验证码还有一分钟时间,吐槽一下简书. 准备开始在简书写文章,遇到一些问题. 一.markdown的问题 1.不支持html 2....... 二.绑定手机--这是一个bug 我原来是使用邮箱注册的, ...

  9. Linux-->磁盘分区,挂载

    Linux分区 原理介绍 Linux无论有几个分区,分给哪一个目录使用,他归根结底都只有一个根目录,一个独立且唯一的文件结构,Linux中每个分区都是用来组成整个文件系统的一部分. Linux采用了一 ...

  10. 【算法】Tarjan

    参考资料: 图论相关概念 - OI WIKI | 强连通分量 - OI WIKI 初探tarjan算法 | Tarjan,你真的了解吗 一.概念 • 子图: 对一张图 \(G=(V,E)\),若存在另 ...