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 编程
服务端编程步骤:
- 创建Socket对象;
- 绑定IP和端口;
- 开始监听
- 建链通信,获取用于传输数据的Socket对象
实现一个简单的TCP server:
import time
import socket
# TCP Server
sock = socket.socket() # step1:创建Socket对象
addr = ('127.0.0.1', 9999)
sock.bind(addr) # step2: 绑定地址&端口
sock.listen() # step3:开始监听
time.sleep(10)
sock.close() # step4:释放资源
使用工具模拟client,实现发送/接收消息:
import socket
import logging
logging.basicConfig(format='%(thread)s %(threadName)s %(message)s', level=logging.INFO)
# TCP Server
sock = socket.socket() # step1:创建Socket对象
addr = ('127.0.0.1', 9999)
sock.bind(addr) # step2: 绑定地址&端口
sock.listen() # step3:开始监听
conn, client_addr = sock.accept() # step4:完成三次握手,建立连接,下面就可以发送/接收数据了。默认是阻塞的,返回一个新对象
logging.info(client_addr)
# 接收消息
data = conn.recv(1024)
logging.info(data.decode())
# 发送消息
msg = 'ack: {}'.format(data.decode())
conn.send(msg.encode())
conn.close()
sock.close()
client 模拟工具:
优化tcp server,实现一个连接发送/接收多次消息:
import socket
import logging
logging.basicConfig(format='[%(thread)s %(threadName)s] %(message)s', level=logging.INFO)
# TCP Server
sock = socket.socket()
ip = '127.0.0.1'
port = 9999
addr = (ip, port)
sock.bind(addr)
sock.listen()
conn, client_addr = sock.accept()
while True:
data = conn.recv(1024).decode()
msg = "[ACK] {}".format(data)
conn.send(msg.encode())
if data == 'Disconnect':
break
conn.close()
sock.close()
注意:上面代码里的 accept() 、recv() 是阻塞性函数(此阻塞是一个I/O请求,或叫I/O密集性阻塞,等网络I/O的缓存区填满到你要求的时候,才可以继续执行后面的程序),主线程经常被阻塞住而不能工作,怎么办呢?
查看某个TCP进程端口的网络状态:netstat -ant | find “9999”