1. Socket 介绍

Socket套接字,是一种通用的网络编程接口,python中提供了socket.py标准库,非常底层的接口库。

接口相关参数:

  • 协议族
  • Socket类型 |
    | 名称 | 含义 | | —- | —- | —- | | 协议族 | AF_INET | IPv4 | | | AF_INET6 | IPv6 | | Socket类型 | SOCK_STREAM | 面向连接的流套接字。默认值是TCP协议 | | | SOCK_DGRAM | 无连接的数据报文套接字。默认为UDP协议 |

Socket编程,一般需要两端,一个服务端Server,一个客户端Client。

2. TCP 编程

服务端编程步骤:

  1. 创建Socket对象;
  2. 绑定IP和端口;
  3. 开始监听
  4. 建链通信,获取用于传输数据的Socket对象

实现一个简单的TCP server:

  1. import time
  2. import socket
  3. # TCP Server
  4. sock = socket.socket() # step1:创建Socket对象
  5. addr = ('127.0.0.1', 9999)
  6. sock.bind(addr) # step2: 绑定地址&端口
  7. sock.listen() # step3:开始监听
  8. time.sleep(10)
  9. sock.close() # step4:释放资源

image.png

使用工具模拟client,实现发送/接收消息:

  1. import socket
  2. import logging
  3. logging.basicConfig(format='%(thread)s %(threadName)s %(message)s', level=logging.INFO)
  4. # TCP Server
  5. sock = socket.socket() # step1:创建Socket对象
  6. addr = ('127.0.0.1', 9999)
  7. sock.bind(addr) # step2: 绑定地址&端口
  8. sock.listen() # step3:开始监听
  9. conn, client_addr = sock.accept() # step4:完成三次握手,建立连接,下面就可以发送/接收数据了。默认是阻塞的,返回一个新对象
  10. logging.info(client_addr)
  11. # 接收消息
  12. data = conn.recv(1024)
  13. logging.info(data.decode())
  14. # 发送消息
  15. msg = 'ack: {}'.format(data.decode())
  16. conn.send(msg.encode())
  17. conn.close()
  18. sock.close()

image.png
image.png

client 模拟工具:image.png

优化tcp server,实现一个连接发送/接收多次消息:

  1. import socket
  2. import logging
  3. logging.basicConfig(format='[%(thread)s %(threadName)s] %(message)s', level=logging.INFO)
  4. # TCP Server
  5. sock = socket.socket()
  6. ip = '127.0.0.1'
  7. port = 9999
  8. addr = (ip, port)
  9. sock.bind(addr)
  10. sock.listen()
  11. conn, client_addr = sock.accept()
  12. while True:
  13. data = conn.recv(1024).decode()
  14. msg = "[ACK] {}".format(data)
  15. conn.send(msg.encode())
  16. if data == 'Disconnect':
  17. break
  18. conn.close()
  19. sock.close()

注意:上面代码里的 accept() 、recv() 是阻塞性函数(此阻塞是一个I/O请求,或叫I/O密集性阻塞,等网络I/O的缓存区填满到你要求的时候,才可以继续执行后面的程序),主线程经常被阻塞住而不能工作,怎么办呢?

查看某个TCP进程端口的网络状态:netstat -ant | find “9999” image.png