Socket(套接字)
介绍 UDP 和 TCP 协议之前,先熟悉下 socket 的基本概念。
- 基本概念
Socket 是通信的基石,是支持 TCP/IP 协议的网络通信的基本操作单元,在网络通信过程中端点的一种抽象表示。网络中使用 Socket 传输数据是一种特殊的网络 I/O。
- 工作模式
打开open -> 读写write/read -> 关闭close
- 五种信息
socket 包括了数据传输必须的五元组,分别为源IP、源端口、目的IP、目的端口和协议号
- 通信机制
基于流(stream)或者基于数据报(datagram)
- python 中使用
import socket socket.socket(...)
UDP
UDP(User Datagram Protocol) 用户数据报协议,是一种面向无连接的协议,提供简单不可靠的信息传输服务,发送后不会确认信息是否到达。
UDP 通信模型中,在通信开始之前,不需要建立相关的链接,只需要发送数据即可,类似于生活中"写信"。
- 使用 socket 使用 UDP 的收发数据,先看原理图
- 客户端代码实现
# 客户端 发送数据 # 1.创建udp套接字 udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) while True: send_data = input("请输入要发送的数据:") if send_data == 'exit': break # 2.发送数据 udp_socket.sendto(send_data.encode(), ("192.168.1.110", 8080)) # 对方的ip和port # 3.关闭套接字 udp_socket.close()
- 服务端代码实现
# 服务端 接收数据 HOST = '' # 空为localhost PORT = 7788 ADDR = (HOST, PORT) BUFSIZE = 1024 # 一次接收最大的尺寸 # 1.创建udp套接字 udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 2.绑定本地套接字信息 udp_socket.bind(ADDR) # 绑定必须是本机的ip和port while True: # 3.接收数据 data, addr = udp_socket.recvfrom(BUFSIZE) # 返回接收数据和发送方的地址信息 if data.decode() == 'exit': print("退出") break # 打印接收的数据 print(f"{addr[0]}:{addr[1]}", data.decode()) # 4.关闭套接字 udp_socket.close()
套接字是可以同时收发数据,是全双工状态,在调用
recvform
之前收到数据,操作系统会将数据暂时储存起来,等到程序调用recvform
取出数据,在调用recvform
之后未接收到数据,程序会进入阻塞状态,等待数据的到来。
TCP
TCP(Transmission Control Protocol)传输控制协议,是一种面向连接的,可靠的、基于字节流的传输层通信协议。
TCP 通信需要经过创建连接、数据传送、终止连接三个步骤。
TCP 通信模型中,在通信开始之前,一定要先建立相关的链接,才能发送数据,类似于生活中"打电话"。 这种连接是一对一的,因此TCP不适用于广播的应用程序,基于广播的应用程序请使用 UDP 协议。
特点:
面向连接(使用三次握手建立连接,连接已创建才作传输,采用四次挥手断开连接。)
- 有序数据传输
- 重发丢失的数据包
- 舍弃重复的数据包
- 无差错的数据传输
阻塞/流量控制
使用 socket 实现 TCP 的收发数据,先看原理图
- 客户端代码实现
# 客户端 IPADDR = "192.168.1.110" PORT = 7788 # 创建套接字 tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 连接服务器,创建连接 tcp_socket.connect((IPADDR, PORT)) # 收发数据 send_data = input("输入发送的数据:") tcp_socket.send(send_data.encode()) # 关闭套接字,关闭连接 tcp_socket.close()
- 服务端代码实现
# 服务端 IPADDR = “” # 默认localhost PORT = 7788 BUFSIZE = 1024 # 一次接收最大的尺寸 print('server start...') # 创建套接字(监听套接字) =》买个手机 tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 绑定本地信息 =》 插入手机卡 tcp_socket.bind((IPADDR, PORT)) # 将手机设为正常,能够响铃 =》 让默认的套接字由主动变为监听 tcp_socket.listen(128) # 同一时间,最大允许连接128个客户端 while True: # 循环为多个客户端服务 print("waitting connected...") # 等待电话到来 =》 等待别人电话的到来,此时程序会被阻塞,等待客户端连接 new_client_socket, client_addr = tcp_socket.accept() # 新的专门为客户端服务的socket,客户端的addr # 接收客户端发送过来的请求,此时程序会阻塞等待客户端发送数据 print("waitting recive data...") while True: # 循环为同一个客户端服务多次 recv_data = new_client_socket.recv(BUFSIZE) # 如果recv 解堵塞,有两种方式 # 1.客户端发送过来数据 # 2.客户端调用close断开连接 if recv_data: print(f"【{client_addr[0]}:{client_addr[1]}】", recv_data.decode()) # 回送一部分数据给客户端 new_client_socket.send('收到'.encode()) else: break # 关闭套接字 new_client_socket.close() print("connect closed") tcp_socket.close() print('server end...')
监听套接字负责等待有新的客户端进行连接
accept
产生的新的套接字用来为客户端服务 如果将监听套接字关闭了,那么会导致不能再次等待新客户端的到来,accept()
会失败 关闭accept
返回的新的套接字,意味着不再为这个客户端服务。
来源:https://www.cnblogs.com/izbw/p/12423682.html