1.TCP协议:
TCP协议规定了数据在传输过程中需要遵循的规则,数据传输过程中能够遵循的协议有很多其中TCP协议和UDP协议是较为常见的两个。
1.1:三次握手
![]()
1.2:四次握手
基于TCP传输数据因为有双向通道所以很安全
TCP传数据不容易丢失因为有二次确认机制 ,每次发送数据都需要返回确认消息否则在一定时间会反复发送
2.UDP协议
UDP协议发送数据没有任何的通道也没有任何的限制,但是没有TCP协议传输数据来的安全(没有二次确认机制)。
eg:发短信重要发送了 不管别人有没有看到也不管回不回复。
应用层提供各种各样的应用层协议,这些协议嵌入在各种我们使用的应用程序中,主要取决程序员自己采用什么策略和协议。
常见协议有:HTTP HTTPS FTP.......
1.scoket套接字的作用
可以看成是两个网络应用程序进行通信时,各自通信连接中的端点
2.套接字家族
基于文件类型的套接字家族
套接字家族的名字:AF_UNIX
基于网络类型的套接字家族
套接字家族的名字:AF_INET
3.代码实现
'''服务端''' import socket # 1.创建一个socket对象 server = socket.socket() # 括号内什么都不写 默认就是基于网络的TCP套接字 # 2.绑定一个固定的地址(ip\port) server.bind(('0.0.0.0', 8080)) # 地址、端口 # 3.半连接池 server.listen(5) # 4.开业 等待接客 sock, address = server.accept() print(sock, address) # sock是双向通道 address是客户端地址 # 5.数据交互 sock.send(b'hello big baby~') # 朝客户端发送数据 data = sock.recv(1024) # 接收客户端发送的数据 1024bytes print(data) # 6.断开连接 sock.close() # 断链接 server.close() # 关机
'''客户端''' import socket # 1.产生一个socket对象 client = socket.socket() # 2.连接服务端(拼接服务端的ip和port) client.connect(('0.0.0.0', 8080)) # 3.数据交互 data = client.recv(1024) # 接收服务端发送的数据 print(data) client.send(b'hello sweet server') # 朝服务端发送数据 # 4.关闭 client.close()4.代码优化
4.1:自定义消息
4.2:循环通信
4.3:服务端保持持续提供服务
4.4:判断输入消息不能为空
'''服务端''' import socket from socket import SOL_SOCKET, SO_REUSEADDR # 1.创建一个socket对象 server = socket.socket() # 括号内什么都不写 默认就是基于网络的TCP套接字 # 2.绑定一个固定的地址(ip\port) server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # 就是它,在bind前加 server.bind(('127.0.0.1', 8080)) # 127.0.0.1本地回环地址(只允许自己的机器访问) # 3.半连接池 server.listen(5) # 4.开业 等待接客 while True: sock, address = server.accept() print(sock, address) # sock是双向通道 address是客户端地址 # 5.数据交互 while True: try: msg = input('请输入发送给客户端的消息>>>:').strip() if len(msg) == 0: continue # 判断输入的是否是空的 sock.send(msg.encode('utf8')) # 朝客户端发送数据 data = sock.recv(1024) # 接收客户端发送的数据 1024bytes if len(data) == 0: # 判断接受的是否是空 break print(data.decode('utf8')) except ConnectionResetError: sock.close() break
'''客户端''' import socket # 1.产生一个socket对象 client = socket.socket() # 2.连接服务端(拼接服务端的ip和port) client.connect(('0.0.0.0', 8080)) # 3.数据交互 while True: data = client.recv(1024) # 接收服务端发送的数据 print(data.decode('utf8')) msg = input('请输入发送给客户端的消息>>>:').strip() if len(msg) == 0: # 判断是否是零 msg = '暂无消息' client.send(msg.encode('utf8')) # 朝服务端发送数据5.半连接池
当服务器在响应了客户端的第一次请求后会进入等待状态,半连接池其实就是一个容器,系统会自动将半连接放入这个容器中,可以避免半连接过多。
server.listen(5) # 自定义数量
1.什么是黏包问题
接收端不知道发送端将要传送的字节流的长度,
UDP不会出现这种情况而TCP协议, 数据流会向流水一样一起, 接收端不清楚每个消息的界限, 不知道每次应该去多少字节的数据。2.TCP特性
流式协议:所有的数据类似于水流一样连接在一起传输(数据量小并且间隔很短就会自动组织到一起)
3.struct模块
Packing(打包成字符串)
Unpacking(解包)
4.黏包解决方法:
'''客户端''' import socket import struct import json client = socket.socket() client.connect(('0.0.0.0', 8080)) while True: # 先接收长度为4的报头数据 header_len = client.recv(4) # 根据报头解包出字典的长度 dict_len = struct.unpack('i', header_len)[0] # 直接接收字典数据 dict_data = client.recv(dict_len) # b'{"file_name":123123123}' # 解码并反序列化出字典 real_dict = json.loads(dict_data) print(real_dict) # 从数据字典中获取真实数据的各项信息 total_size = real_dict.get('file_size') # 32423423423 file_size = 0 with open(r'文件路径', 'wb') as f: while file_size < total_size: data = client.recv(1024) f.write(data) file_size += len(data) print('文件接收完毕') break
'''服务端''' import socket import os import struct import json server = socket.socket() server.bind(('0.0.0.0', 8080)) server.listen(5) while True: sock, address = server.accept() while True: # 构造数据文件的字典 file_dict = { 'file_name': 'a.txt', 'file_size': os.path.getsize(r'文件绝对路径') } # 将字典转换成json格式 dict_json = json.dumps(file_dict) file_bytes_dict = len(dict_json.encode('utf8')) # 将字典打包成固定长度的数据 dict_len = struct.pack('i', file_bytes_dict) # 发送固定长度的字典报头 sock.send(dict_len) # 发送真实字典数据 sock.send(dict_json.encode('utf8')) # 发送真实数据 with open(r'读取文件', 'rb') as f: for line in f: sock.send(line) break