利用python实现socket通信,需要实现客户端和服务端。通常,服务端不仅仅是为一个客户端服务,可能同时为多个客户端提供连接服务,在python中常见的提供多连接的方式有进程、线程、协程以及select和poll实现的异步I/O。这篇文章,主要介绍使用进程、线程、协程实现的socket多连接通信。
首先,这里先介绍一下进程、线程、协程的区别?(https://my.oschina.net/u/4543837/blog/4465255)
进程:操作系统提供的抽象概念,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。程序是指令、数据及其组织形式的描述,进程是程序的实体。程序本身是没有生命周期的,它只是存在磁盘上的一些指令,程序一旦运行就是进程。
线程:也是操作系统提供的抽象概念,是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。一个进程可以有一个或多个线程,同一进程中的多个线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。
协程(Coroutine,又称微线程)是一种比线程更加轻量级的存在,协程不是被操作系统内核所管理,而完全是由程序所控制。协程与线程以及进程的关系见下图所示。

-  协程可以比作子程序,但执行过程中,子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。协程之间的切换不需要涉及任何系统调用或任何阻塞调用 
-  协程只在一个线程中执行,是子程序之间的切换,发生在用户态上。而且,线程的阻塞状态是由操作系统内核来完成,发生在内核态上,因此协程相比线程节省线程创建和切换的开销 
-  协程中不存在同时写变量冲突,因此,也就不需要用来守卫关键区块的同步性原语,比如互斥锁、信号量等,并且不需要来自操作系统的支持。 
协程适用于IO阻塞且需要大量并发的场景,当发生IO阻塞,由协程的调度器进行调度,通过将数据流yield掉,并且记录当前栈上的数据,阻塞完后立刻再通过线程恢复栈,并把阻塞的结果放到这个线程上去运行。
进程实现tcp socket通信
server
  
   - 
    
     
    
    
     
      import socket
     
    
- 
    
     
    
    
     
      from multiprocessing 
      import Process
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      class ServerProcess:
     
    
- 
    
     
    
    
         
      def __init__(self, ipaddr, port, num):
     
    
- 
    
     
    
    
     
              self.ipaddr = ipaddr
     
    
- 
    
     
    
    
     
              self.port = port
     
    
- 
    
     
    
    
     
              self.num = num
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      # 服务端的数据接收,在调用时使用多进程
     
    
- 
    
     
    
    
         
      def server_link(self, conn, addr):
     
    
- 
    
     
    
    
     
              conn.send(
      "Welcome connect!".encode())
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
             
      while 
      True:
     
    
- 
    
     
    
    
                 
      try:
     
    
- 
    
     
    
    
     
                      data = conn.recv(
      1024)
     
    
- 
    
     
    
    
                     
      if data:
     
    
- 
    
     
    
    
     
                          print(
      "from {0}:".format(addr), data.decode(
      'utf-8'))
     
    
- 
    
     
    
    
                     
      else:
     
    
- 
    
     
    
    
                         
      break
     
    
- 
    
     
    
    
                 
      except Exception:
     
    
- 
    
     
    
    
                     
      break
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
              conn.close()
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      # 服务端的启动程序
     
    
- 
    
     
    
    
         
      def server_start(self):
     
    
- 
    
     
    
    
             
      # IPv4
     
    
- 
    
     
    
    
     
              s_pro = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     
    
- 
    
     
    
    
             
      # 操作系统会在服务器socket被关闭或服务器进程终止后马上释放该服务器的端口
     
    
- 
    
     
    
    
     
              s_pro.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 
      1)
     
    
- 
    
     
    
    
     
              s_pro.bind((self.ipaddr, self.port))
     
    
- 
    
     
    
    
     
              s_pro.listen(self.num)
     
    
- 
    
     
    
    
     
              print(
      'Waiting link...')
     
    
- 
    
     
    
    
             
      while 
      True:
     
    
- 
    
     
    
    
     
                  conn, addr = s_pro.accept()
     
    
- 
    
     
    
    
     
                  print(
      "Success connect from ", addr)
     
    
- 
    
     
    
    
                 
      # 启动多进程实现多连接
     
    
- 
    
     
    
    
     
                  p = Process(target=self.server_link, args=(conn, addr))
     
    
- 
    
     
    
    
     
                  p.start()
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      if __name__ == 
      '__main__':
     
    
- 
    
     
    
    
     
          server = ServerProcess(
      '127.0.0.1', 
      12345, 
      5)
     
    
- 
    
     
    
    
     
          server.server_start()
     
    
线程实现tcp socket通信
server
  
   - 
    
     
    
    
     
      import socket
     
    
- 
    
     
    
    
     
      import threading
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      class ServerThread:
     
    
- 
    
     
    
    
         
      def __init__(self, ipaddr, port, num):
     
    
- 
    
     
    
    
     
              self.ipaddr = ipaddr
     
    
- 
    
     
    
    
     
              self.port = port
     
    
- 
    
     
    
    
     
              self.num = num
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      def server_link(self, conn, addr):
     
    
- 
    
     
    
    
     
              conn.send(
      "Welcome connect!".encode())
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
             
      while 
      True:
     
    
- 
    
     
    
    
                 
      try:
     
    
- 
    
     
    
    
     
                      data = conn.recv(
      1024)
     
    
- 
    
     
    
    
                     
      if data:
     
    
- 
    
     
    
    
     
                          print(
      "from {0}:".format(addr), data.decode(
      'utf-8'))
     
    
- 
    
     
    
    
                     
      else:
     
    
- 
    
     
    
    
                         
      break
     
    
- 
    
     
    
    
                 
      except Exception:
     
    
- 
    
     
    
    
                     
      break
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
              conn.close()
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      def server_start(self):
     
    
- 
    
     
    
    
     
              s_pro = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     
    
- 
    
     
    
    
     
              s_pro.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 
      1)
     
    
- 
    
     
    
    
     
              s_pro.bind((self.ipaddr, self.port))
     
    
- 
    
     
    
    
     
              s_pro.listen(self.num)
     
    
- 
    
     
    
    
     
              print(
      'Waiting link...')
     
    
- 
    
     
    
    
             
      while 
      True:
     
    
- 
    
     
    
    
     
                  conn, addr = s_pro.accept()
     
    
- 
    
     
    
    
     
                  print(
      "Success connect from ", addr)
     
    
- 
    
     
    
    
     
                  p = threading.Thread(target=self.server_link, args=(conn, addr))
     
    
- 
    
     
    
    
     
                  p.start()
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      if __name__ == 
      '__main__':
     
    
- 
    
     
    
    
     
          server = ServerThread(
      '127.0.0.1', 
      12345, 
      5)
     
    
- 
    
     
    
    
     
          server.server_start()
     
    
协程实现tcp socket通信
server
  
   - 
    
     
    
    
     
      import socket
     
    
- 
    
     
    
    
     
      import asyncio
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      class ServerProcess:
     
    
- 
    
     
    
    
         
      def __init__(self, ipaddr, port, num):
     
    
- 
    
     
    
    
     
              self.ipaddr = ipaddr
     
    
- 
    
     
    
    
     
              self.port = port
     
    
- 
    
     
    
    
     
              self.num = num
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      async 
      def server_link(self, conn, addr):
     
    
- 
    
     
    
    
     
              conn.send(
      "Welcome connect!".encode())
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
             
      while 
      True:
     
    
- 
    
     
    
    
                 
      try:
     
    
- 
    
     
    
    
     
                      data = conn.recv(
      1024)
     
    
- 
    
     
    
    
                     
      if data:
     
    
- 
    
     
    
    
     
                          print(
      "from {0}:".format(addr), data.decode(
      'utf-8'))
     
    
- 
    
     
    
    
                     
      else:
     
    
- 
    
     
    
    
                         
      break
     
    
- 
    
     
    
    
                 
      except Exception:
     
    
- 
    
     
    
    
                     
      break
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
              conn.close()
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      def server_start(self):
     
    
- 
    
     
    
    
     
              s_pro = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     
    
- 
    
     
    
    
     
              s_pro.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 
      1)
     
    
- 
    
     
    
    
     
              s_pro.bind((self.ipaddr, self.port))
     
    
- 
    
     
    
    
     
              s_pro.listen(self.num)
     
    
- 
    
     
    
    
     
              print(
      'Waiting link...')
     
    
- 
    
     
    
    
             
      while 
      True:
     
    
- 
    
     
    
    
     
                  conn, addr = s_pro.accept()
     
    
- 
    
     
    
    
     
                  print(
      "Success connect from ", addr)
     
    
- 
    
     
    
    
     
                  loop = asyncio.get_event_loop()
     
    
- 
    
     
    
    
     
                  loop.run_until_complete(self.server_link(conn, addr))
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      if __name__ == 
      '__main__':
     
    
- 
    
     
    
    
     
          server = ServerProcess(
      '127.0.0.1', 
      12345, 
      5)
     
    
- 
    
     
    
    
     
          server.server_start()
     
    
对于以上三种方式实现的服务端,客户端这里我都采用同样的代码,可以写多个客户端测试socket通信的并发性。
client
  
   - 
    
     
    
    
     
      import socket
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      class Client1:
     
    
- 
    
     
    
    
         
      def __init__(self, ipaddr, port):
     
    
- 
    
     
    
    
     
              self.ipaddr = ipaddr
     
    
- 
    
     
    
    
     
              self.port = port
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      def client_link(self):
     
    
- 
    
     
    
    
     
              c1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     
    
- 
    
     
    
    
     
              c1.connect((self.ipaddr, self.port))
     
    
- 
    
     
    
    
     
              print(
      'receive info:', c1.recv(
      1024).decode(
      'utf-8'))
     
    
- 
    
     
    
    
             
      while 
      True:
     
    
- 
    
     
    
    
     
                  info = input(
      'enter info:')
     
    
- 
    
     
    
    
     
                  c1.send(info.encode())
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      if __name__ == 
      '__main__':
     
    
- 
    
     
    
    
     
          c = Client1(
      '127.0.0.1', 
      8888)
     
    
- 
    
     
    
    
     
          c.client_link()
     
    
转载:https://blog.csdn.net/weixin_40042248/article/details/115337135
