socket
背景概念
脑图结构
OSI 模型
socket 概念特性
脑图结构
理解示意图
额外补充
Socket是应用层与 TCP/IP协议族通信的中间软件抽象层,它是一组接口。
在设计模式中, Socket其实就是一个门面模式
它把复杂的 TCP/IP协议族隐藏在 Socket接口后面,对用户来说,一组简单的接口就是全部,让 Socket去组织数据,以符合指定的协议。
TCP_socket
server
import socket sk = socket.socket() sk.bind(('127.0.0.1',8898)) # 把地址绑定到套接字 sk.listen() # 监听链接 conn,addr = sk.accept() # 接受客户端链接 ret = conn.recv(1024) # 接收客户端信息 print(ret) # 打印客户端信息 conn.send(b'hi') # 向客户端发送信息 conn.close() # 关闭客户端套接字 sk.close() # 关闭服务器套接字(可选)client
import socket sk = socket.socket() # 创建客户套接字 sk.connect(('127.0.0.1',8898)) # 尝试连接服务器 sk.send(b'hello!') ret = sk.recv(1024) # 对话(发送/接收) print(ret) sk.close() # 关闭客户套接字特性
粘包
额外补充
TCP (Transmission Control Protocol)可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。
使用TCP的应用:Web浏览器;电子邮件、文件传输程序。
UDP_socket
server
import socket udp_sk = socket.socket(type=socket.SOCK_DGRAM) #创建一个服务器的套接字 udp_sk.bind(('127.0.0.1',9000)) #绑定服务器套接字 msg,addr = udp_sk.recvfrom(1024) print(msg) udp_sk.sendto(b'hi',addr) # 对话(接收与发送) udp_sk.close() # 关闭服务器套接字client
import socket ip_port=('127.0.0.1',9000) udp_sk=socket.socket(type=socket.SOCK_DGRAM) udp_sk.sendto(b'hello',ip_port) back_msg,addr=udp_sk.recvfrom(1024) print(back_msg.decode('utf-8'),addr)额外补充
UDP (User Datagram Protocol)不可靠的、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文,尽最大努力服务,无拥塞控制。
使用UDP的应用:域名系统 (DNS);视频流;IP语音(VoIP)。
其他补充方法
文本笔记
socket概念 套接字:实现网络编程进行数据传输的一种技术手段 相关模块: import socket 分类 流式套接字(SOCK_STREAM): 以字节流方式传输数据,实现tcp网络传输方案。 数据报套接字(SOCK_DGRAM):以数据报形式传输数据,实现udp网络传输方案。 面向连接--tcp协议--可靠的--流式套接字 无连接--udp协议--不可靠--数据报套接字 tcp套接字编程 服务端流程 1. 创建套接字 sk = socket.socket(socket_family=AF_INET,socket_type=SOCK_STREAM,proto=0) 功能: 创建套接字 参数: socket_family 网络地址类型 AF_INET-->ipv4 socket_type 选择类型,与 TCP/UDP 中选择, 默认就是 TCP 模式 套接字类型 SOCK_STREAM 流式(TCP) SOCK_DGRAM 数据报(UDP) proto 通常为0,可以忽略 选择子协议 返回值: 套接字对象 2. 绑定地址 sk.bind(addr) 功能: 绑定本机网络地址 参数: 二元元组 (ip,port) 例如:('0.0.0.0',8888) 3. 设置监听 sk.listen(n) 功能 : 将套接字设置为监听套接字,确定监听队列大小 参数 : 监听队列大小 4. 等待处理客户端连接请求 conn,addr = sk.accept() 功能: 阻塞等待处理客户端请求 返回值: conn 客户端连接套接字 addr 连接的客户端地址 * 阻塞函数 : 程序运行过程中遇到阻塞函数则暂停执行,直到达成某种条件后继续运行。 5. 消息收发 data = conn.recv(buffersize) 功能 : 接受客户端消息 参数 :每次最多接收消息的大小 返回值: 接收到的内容 n = conn.send(data) 功能 : 发送消息 参数 :要发送的内容 bytes格式 返回值: 发送的字节数 * str --> bytes string.encode() bytes --> str bytes.decode() 6. 关闭套接字 sk.close() 功能:关闭套接字 """ import socket sk = socket.socket() sk.bind(("127.0.0.1", 8008)) sk.listen() conn, addr = sk.accept() conn.send(b"hello") conn.close() sk.close() """ 客户端流程 1. 创建套接字 sk = socket.socket() * 只有相同类型的套接字才能进行通信 2. 请求连接 sk.connect(server_addr) 功能:连接服务器 参数:元组 服务器地址 3. 收发消息 print(sk.recv(1024)) * 防止两端都阻塞,recv send要配合 4. 关闭套接字 """ import socket sk = socket.socket() sk.connect(("127.0.0.1", 8008)) print(sk.recv(1024)) sk.close() """ 代码流程总结 服务端:socket() --> bind() --> listen() --> accept() --> recv(),send() --> close() 客户端:socket() --> connect() --> send(),recv() --> close() 整体过程总结 * tcp连接中当一端退出,另一端如果阻塞在recv,此时recv会立即返回一个空字串。 * tcp连接中如果一端已经不存在,让然试图通过send发送则会产生BrokenPipeError * 一个监听套接字可以同时连接多个客户端,也能够重复被连接 * 网络收发缓冲区 【1】网络缓冲区有效的协调了消息的收发速度 【2】send和recv实际是向缓冲区发送接收消息,当缓冲区不为空recv就不会阻塞。 * tcp粘包 【1】 原因:tcp以字节流方式传输,没有消息边界。多次发送的消息被一次接收,此时就会形成粘包。 【2】 影响:如果每次发送内容是一个独立的含义,需要接收端独立解析此时粘包会有影响。 【3】 处理: 1. 人为的添加消息边界 2. 控制发送速度 UDP套接字编程 服务端流程 1. 创建数据报套接字 sk = socket(AF_INET,SOCK_DGRAM) 2. 绑定地址 sk.bind(addr) 3. 消息收发 data,addr = sockfd.recvfrom(buffersize) 功能: 接收UDP消息 参数: 每次最多接收多少字节 返回值: data 接收到的内容 addr 消息发送方地址 n = sockfd.sendto(data,addr) 功能: 发送UDP消息 参数: data 发送的内容 bytes格式 addr 目标地址 返回值:发送的字节数 4. 关闭套接字 sockfd.close() """ import socket udp_sk = socket.socket(type=socket.SOCK_DGRAM) udp_sk.bind(('127.0.0.1', 9000)) msg, addr = udp_sk.recvfrom(1024) print(msg) udp_sk.sendto(b'hi', addr) udp_sk.close() """ 客户端流程 1. 创建套接字 sk=socket.socket(type=socket.SOCK_DGRAM) 2. 收发消息 sk.sendto(data,("127.0.0.1",8000)) sk.recvfrom(1024) 3. 关闭套接字 sk.close() """ import socket sk = socket.socket(type=socket.SOCK_DGRAM) addr = ("127.0.0.1", 9000) sk.sendto(b"hello", addr) data, addr = sk.recvfrom(1024) print(data) sk.close() """