python socket 通信(发送文字、图片、文件)
1、IP/TCP/UDP简介
1.1、IP协议
互联网上每个计算机的唯一标识就是 IP 地址。IP 地址实际上是一个32位整数(称为IPv4),它是以字符串表示的 IP 地址,如:172.16.254.1,实际上是把32位整数按8位分组后得到的。如 图1.1.1所示:
图1.1.1 IPv4示例
IP 协议负责把数据从一台计算机通过网络发送到另一台计算机。数据被分割成一小块一小块。类似于将一个大包裹拆分成几个小包裹,然后通过 IP 包发送出去。
IP 包的特点是按块发送,途径多个路由,但不保证都能到达,也不能保证顺序到达。
1.2、TCP协议
TCP 协议是建立在 IP 协议之上的。TCP 协议负责在两台计算机之间建立可靠连接,保证数据包按顺序到达。TCP 协议会通过3次握手建立可靠连接。如 图1.2所示:
图 1.2.1 TCP 三次握手
传输时需要对每个 IP 包进行编号,确保对方按顺序收到,如果包丢掉了,就自动重发。如 图1.2.2所示:
图 1.2.2 传输数据包
一个 TCP 报文除了要包含传输的数据,还要包含源 IP 地址和目标 IP 地址、源端口和目标端口。每个网络程序都向操作系统申请唯一的端口号,这样两个进程在两台计算机之间建立网络连接就需要各自的 IP 地址和各自的端口号。
一个进程也可能同时与多个计算机建立连接,因此他会申请很多端口。端口号不是随意使用的,二十按照一定的规矩进行分配。例如:80端口分配给HTTP服务,21端口分配给FTP服务。
1.3、UDP协议
UDP 协议时面向无连接的协议。使用 UDP 协议时,不需要建立连接,子需要自动对方的 IP 地址和端口号,就可以直接发送数据包。但是无法保证数据一定到达。
虽然用 UDP 传输数据不可靠,但是它的有点是比 TCP 协议熟读快。对于不要求可靠到达的数据而言,就可以使用 UDP 协议。
TCP 协议和 UDP 协议的区别,如 图1.3.1所示:
图1.3.1 TCP协议和UDP协议的区别
2、socket简介
为了让两个程序通过网络进行通信,二者均必须使用 Socket 套接字。Socket 的英文原义是“孔”或“插座“,通常业称作”套接字“,用于描述 IP 地址和端口,它是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。如 图2.1所示:
图2.1 使用Socket实现通信
3、关键函数
s = socket.socket(AddressFamily,Type)
AddressFamily:可以选择 AF_INET(用于Internet进程间通信)或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用 AF_INET
Type:套接字类型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或则SOCK_DGRAM(数据包套接字,主要用于 UDP 协议)
# 创建TCP/IP套接字
tcpSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 创建UDP/IP套接字
udpSocket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
socket 对象的内置方法:
函数 | 描述 |
---|---|
s.bind() | 绑定地址(host,port)到套接字,在 AF_INET 下,以元组(host,port)的形式表示地址 |
s.listen() | 开始 TCP 监听。backlog 指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分要用程序设为5即可i |
s.accept() | 被动接受 TCP 客户端连接(阻塞式),等待连接的到来 |
s.connect() | 主动初始化 TCP 服务器连接,一般 address 的格式为元组(host,port),如果连接出错,返回 socket.error 错误 |
s.recv() | 接受 TCP 数据,数据以字符串 形式返回,bufsize 指定要接收的最大数据量,flag 提供有关消息的其他信息,通常可以忽略 |
s.send() | 发送 TCP 数据,将 string 中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小 |
s.sendall() | 完整发送 TCP 数据,将 string 中的数据发送到 连接的套接字,但在返回之前会尝试发送所有数据。成功返回 None,失败则抛出异常 |
s.recvfrom() | 接收 UDP 数据,与 recv() 类似,单返回值是(data,address)。其中 data 是包含接收数据的字符串,addrress 是发送数据的套接字 |
s.sendto() | 发送 UDP 数据,将数据发送到套接字,address 是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数 |
s.close() | 关闭套接字 |
4、发送文字
4.1、单次发送接收
客户端:
def SingleSendText():"""单次发送接收文字"""# host = socket.gethostname() # 获取主机地址 socket.gethostname()host = "192.168.10.1" # 设置IPport = 6666 # 设置端口号tcpclient = socket.socket() # 创建TCP/IP套接字tcpclient.connect((host, port)) # 主动初始化TCP服务器连接print("已连接服务端")send_data = input("请输入要发送的内容:")tcpclient.send(send_data.encode()) # 发送TCP数据info = tcpclient.recv(1024).decode()print("接收到的内容:", info)tcpclient.close()
服务端:
def SingleReceiveText():"""单次接收发送文字"""# host = socket.gethostname() # 获取主机地址 socket.gethostname()host = "192.168.10.1" # 设置IPport = 6666 # 设置端口号tcpserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建TCP/IP套接字tcpserver.bind((host, port)) # 绑定地址(host, port)到套接字tcpserver.listen(5) # 设置最多连接数量print("等待客户端连接...")tcpclient, addr = tcpserver.accept() # 被动接收TCP客户端连接print("客户端已经连接")info = tcpclient.recv(1024).decode() # 接收客户端数据print("接收到的内容:", info)send_data = input("请输入要发送的内容:")tcpclient.send(send_data.encode()) # 发送TCP数据tcpclient.close()tcpserver.close()
效果:
4..2、循环发送接收
客户端:
def CycleSendText():"""循环发送接收文字"""# host = socket.gethostname() # 获取主机地址 socket.gethostname()host = "192.168.10.1" # 设置IPport = 6666 # 设置端口号tcpclient = socket.socket() # 创建TCP/IP套接字tcpclient.connect((host, port)) # 主动初始化TCP服务器连接print("已连接服务端")while True: # 判断是否退出send_data = input("请输入要发送的内容:")tcpclient.send(send_data.encode()) # 发送TCP数据if send_data == "byebye":breakinfo = tcpclient.recv(1024).decode()if info == "byebye":breakelse:print("接收到的内容:", info)tcpclient.close()
服务器:
def ReceiveTextCircularly():"""循环接收发送文字"""# host = socket.gethostname() # 获取主机地址 socket.gethostname()host = "192.168.10.1" # 设置IPport = 6666 # 设置端口号tcpserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建TCP/IP套接字tcpserver.bind((host, port)) # 绑定地址(host, port)到套接字tcpserver.listen(5) # 设置最多连接数量print("等待客户端连接...")tcpclient, addr = tcpserver.accept() # 被动接收TCP客户端连接print("客户端已经连接")while True: # 判断是否退出info = tcpclient.recv(1024).decode() # 接收客户端数据if info == "byebye":breakprint("接收到的内容:", info)send_data = input("请输入要发送的内容:")tcpclient.send(send_data.encode()) # 发送TCP数据if send_data == "byebye":breaktcpclient.close()tcpserver.close()
效果:
5、发送图片
5.1、单次发送接收
客户端:
def SingleSendPicture():"""单次发送图片"""host = "192.168.10.1" # 设置IPport = 6666 # 设置端口号tcpclient = socket.socket() # 创建TCP/IP套接字tcpclient.connect((host, port)) # 主动初始化TCP服务器连接print("已连接服务端")imgPath = "people.jpg"sdata = picture2base(imgPath)print(f"开始发送图片 {imgPath}")tcpclient.send(sdata.encode())tcpclient.close()print("发送完成")
服务端:
def SingleReceivePicture():"""单次接收图片"""host = "192.168.10.1" # 设置IPport = 6666 # 设置端口号tcpserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建TCP/IP套接字tcpserver.bind((host, port)) # 绑定地址(host, port)到套接字tcpserver.listen(5) # 设置最多连接数量print("等待客户端连接...")tcpclient, addr = tcpserver.accept() # 被动接收TCP客户端连接print("客户端已经连接")print("开始接收")base64_data = ""while True:rdata = tcpclient.recv(1024)base64_data += str(rdata, 'utf-8')if not rdata:breakbase2picture(base64_data)tcpclient.close()tcpserver.close()print("接收完成")
5.2、循环接收
客户端:
def CycleSendPictures():"""发送图片"""host = "192.168.10.1" port = 6666tcpclient = socket.socket() tcpclient.connect((host, port)) print("已连接服务端")imgPath = "people.jpg"sdata = picture2base(imgPath)print(f"开始发送图片 {imgPath}")tcpclient.send(sdata.encode())tcpclient.close()print("发送完成")
服务端:
def ReceivePicturesCircularly():"""循环接收图片"""host = "192.168.10.1"port = 6666tcpserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM)tcpserver.bind((host, port))tcpserver.listen(5)print("等待客户端连接...")while True:tcpclient, addr = tcpserver.accept()print("-"*5 + "开始接收" + "-"*5)base64_data = ""while True:rdata = tcpclient.recv(1024)base64_data += str(rdata, 'utf-8')if not rdata:breakbase2picture(base64_data)tcpclient.close()print("-"*5 + "接收完成" + "-"*5)tcpserver.close()
6、发送文件
客户端:
def SendFile():"""发送文件"""host = "192.168.10.1"port = 6666tcpclient = socket.socket()try:tcpclient.connect((host, port))print('服务器已连接')except:print('服务器连接失败,请修改后重新运行!!')exit(0)while True:print("-" * 5 + "开始发送" + "-" * 5)filename = "qq.txt"print(f"发送的文件为:{filename}")with open(filename, "r", encoding="utf-8") as f:rdata = f.read()tcpclient.send("qq.txt".encode("utf-8"))if tcpclient.recv(1024).decode("utf-8") == "ok":while True:tcpclient.send(rdata.encode('utf-8'))breakprint("-" * 5 + "发送完成" + "-" * 5)breaktcpclient.close()
服务端:
def ReceivingFile():"""接收文件"""host = "192.168.10.1"port = 6666tcpserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM)tcpserver.bind((host, port))tcpserver.listen(5)print("等待客户端连接...")while True:tcpclient, addr = tcpserver.accept()print('client addr:', addr)while True:print("-" * 5 + "开始接收" + "-" * 5)fileNameData = tcpclient.recv(1024) # 接收文件名字filename = fileNameData.decode('utf-8')new_filename = "new_" + filenameprint(f"文件保存为:{new_filename}")if os.path.exists(new_filename):os.remove(new_filename)new_file = open(new_filename, "a", encoding="utf-8")tcpclient.send("ok".encode("utf-8"))while True:rdata = tcpclient.recv(1024) # 接收文件内容if not rdata:breaknew_file.write(rdata.decode("utf-8"))new_file.close()print("-" * 5 + "接收完成" + "-" * 5)breaktcpclient.close()# break # 注释则可以循环接收tcpserver.close()
7、源码获取
Socket通信(文字、图片、文件)
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!