TCP和UDP两个协议下的套接字
TCP和UDP对比
- TCP(Transmission Control Protocol)
- 可靠的、面向连接的协议。低效的全双工通信(接收缓存、发送缓存)。面向字节流。
- 应用:Web浏览器,文件传输程序
- UDP(User Datagram Protocol)
- 不可靠的、无连接的协议。传输效率高(发送时延小)。一对一、一对多、多对一、多对多,面向报文(数据包)。尽力而为的传输,无拥塞控制。
- 应用:域名系统(DNS)、视频流。
套接字的函数
s是一个socket对象。
服务端套接字函数
| s.bind() | 绑定(主机,端口号)到套接字 |
|---|---|
| s.listen() | 监听端口 |
| s.accept() | 阻塞式,等待TCP客户端的连接 |
客户端套接字函数
| s.connect() | 向服务端发起连接 |
|---|---|
| s.connect_ex() | connect()函数的扩展版,错误时返回错误码,而不是抛出异常。 |
公共用途套接字函数
| s.recv() | TCP接收数据 |
|---|---|
| s.send() | TCP发送数据,待发送数据量大于缓存区剩余空间时,数据丢失,不会发完。 |
| s.sendall() | TCP发送完整数据,本质是循环调用send函数直至数据发完。 |
| s.recvfrom() | UDP接受数据 |
| s.sendto() | UDP发送数据 |
| s.getpeername() | 获取当前套接字的远端地址 |
| s.getsockname() | 获取当前套接字的地址 |
| s.getsockopt() | 获取当前套接字的参数 |
| s.setsockopt() | 设置当前套接字的参数 |
| s.close() | 关闭套接字 |
面向锁的套接字函数
| s.setblocking() | 设置套接字的阻塞与非阻塞模式 |
|---|---|
| s.settimeout() | 设置阻塞套接字操作的超时时间 |
| s.gettimeout() | 获取阻塞套接字操作的超时时间 |
面向文件的套接字函数
| s.fileno() | 套接字的文件描述符 |
|---|---|
| s.makefile() | 创建一个与该套接字相关的文件 |
TCP协议下的socket

- 一次交互:
服务器先初始化socket对象,然后绑定端口(bind),对端口进行监听,调用accept()阻塞,等待客户端连接。
客户端初始化socket对象,向服务器发出连接请求,成功的话连接就建立好了。
连接建立后,客户端向服务器请求数据,服务器接受请求并处理后,回应数据给客户端,客户端读取数据后关闭连接,服务器监听到了后也关闭连接(close)。
import socket# 导入socket包socket.socket(socket_family, socket_type, protocal = 0)# 初始化socket对象,socket_family可以是AF_UNIX或AF_INET(本机通信或联机通信),# socket_type可以是SOCK_STREAM或SOCK_DGRAM(TCP或UDP)。protocal一般不填默认为0.# 初始化socket对象,获取TCP套接字tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 初始化socket对象,获取UDP套接字udp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# socket模块里有太多属性了,所以我们可以通过from socket import *将模块里的所有属性带到命名空间里from socket import *tcp_sock = socket(AF_INET, SOCK_STREAM)
案例一:单个客户端与服务端通信
服务端
import socketphone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 初始化socket对象 买电话phone.bind(('127.0.0.1', 8080))# 绑定(主机地址,端口号) 装电话卡phone.listen(5)# 监听端口,同一时刻有5个请求,但是可以有多个连接 开机conn, client_addr = phone.accept()# 阻塞等待客户端连接,接收到的是远端套接字和客户端地址 接电话print(conn, client_addr, sep = '\n')from_client_data = conn.recv(1024)# 一次接收最大限制 1024 bytesprint(from_client_data.decode('utf-8'))conn.send(from_client_data.upper())conn.close()# 挂电话phone.close()# 关机
客户端
import socketphone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 初始化socket对象 买电话phone.connect(('127.0.0.1', 8080))# 与服务端建立连接 拨号phone.send('hello'.encode('utf-8'))# 发送消息hello,编码utf-8from_server_data = phone.recv(1024)print(from_server_data)phone.close()# 关机
案例二:循环通信
案例一客户端发送一个消息就会断开连接
通过循环来保持连接状态
服务端
import socketphone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)phone.bind(('127.0.0.1', 8080))phone.listen(5)conn, client_addr = phone.accept()print(conn, client_addr, sep='\n')while True:try:from_client_data = conn.recv(1024)print(from_client_data.decode('utf-8'))conn.send(from_client_data.upper())except ConnectionResetError:breakconn.close()phone.close()
客户端
import socketphone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)phone.connect(('127.0.0.1', 8080))while True:client_data = input('>>> ')phone.send(client_data.encode('utf-8'))from_server_data = phone.recv(1024)print(from_server_data.decode('utf-8'))phone.close()
