随笔- 72  文章- 0  评论- 0  阅读- 6779 
  • 目录
    • OSI七层协议
    • socket套接字编程
    • 通信操作(cs架构)
    • 黏包问题及解决办法
  • OSI七层协议之传输层

   1.传输层之TCP协议:需要建立双向通道(相当于打电话)

    数据安全性:客户端与服务端数据传输会建立不同的通道并且会在相互传输时做备份并且会反复确认是否收到数据,等对方收到数据后才会删除备份

    数据传输之三次握手与四次挥手

            三次握手

    

           四次挥手

    

   2.传输层之UDP协议:数据传输没有限制(相当于发短信)

    数据不安全性:客户端与服务端传输不会建立通道,通过网络传输并且互相不进行备份,传输后直接删除数据

  •  OSI七层协议之应用层:取决于程序员采用什么样的方法和策略

   1.常见协议有:HTTP HTTPS FTP...

  • socket套接字编程

   1.类型:

    基于文件类型的套接字家族:AF_UNIX

    基于网络类型的套接字家族:AF_INET

   2.推理一 

复制代码
服务端:
import socket

# 推理一# 创建一个socket对象

server = socket.socket()   # 创建对象中的参数都是关键字参数所以不需要传输据
# 绑定访问的ip地址 server.bind(('127.0.0.1', 8090)) # ip地址,端口号# # 半连接池(允许访问的客户端数量) server.listen(8) # 数据传输通道并获得用户地址 sock, addr = server.accept() # 数据交互(发送与接收数据) sock.send(b'hahhaha') # b'aaaa' date = sock.recv(1024) # 接收数据的字节数 print(date) # 关闭交互(断连接与关机) sock.close() server.close() 客户端: import socket # 创建对象 client = socket.socket() # 连接服务器(ip地址与port端口号) client.connect(('127.0.0.1', 8090)) # 循环交互 while True: # 数据交互(接收与发送数据) date = client.recv(1024) print(date.decode('utf8')) # 获得输入的数据 client.send(b'xixixi')
复制代码

   3.推理二

复制代码
服务端:
import socket

# 优化-交互循环#
 创建一个socket对象
server = socket.socket()  # 创建对象中的参数都是关键字参数所以不需要传输据
# 绑定访问的ip地址 server.bind(('127.0.0.1', 8090)) # ip地址,端口号
# 半连接池(允许访问的客户端数量) server.listen(8) # 数据传输通道并获得用户地址 sock, addr = server.accept() # 数据交互(发送与接收数据)# 循环交流 while True: # 获得输入的数据 info = input('请输入信息>>>:').strip() sock.send(info.encode('utf8')) # b'aaaa' date = sock.recv(1024) # 接收数据的字节数 print(date.decode('utf8')) 客户端: import socket # 创建对象 client = socket.socket() # 连接服务器(ip地址与port端口号) client.connect(('127.0.0.1', 8090)) # 循环交互 while True: # 数据交互(接收与发送数据) date = client.recv(1024) print(date.decode('utf8')) # 获得输入的数据 info = input('请输入信息>>>:').strip() client.send(info.encode('utf8'))
复制代码

   4.推理三

复制代码
服务端:
# 优化-客户端终止后服务端报错采用异常捕获处理(返回到接收新用户端操作)并判断是否敲空格
# 优化-交互循环
# 创建一个socket对象
server = socket.socket()  # 创建对象中的参数都是关键字参数所以不需要传输据
# 绑定访问的ip地址
server.bind(('127.0.0.1', 8090))  # ip地址,端口号
# 半连接池(允许访问的客户端数量)
server.listen(8)
while True:
    # 数据传输通道并获得用户地址
    sock, addr = server.accept()
    # 数据交互(发送与接收数据)
    # 循环交流
    while True:
        # 采用异常捕获处理错误
        try:
            # 获得输入的数据
            info = input('请输入信息>>>:').strip()
            # 若没有输入数据敲了空格,进行判断
            if len(info) == 0:
                continue
            sock.send(info.encode('utf8'))  # b'aaaa'
            date = sock.recv(1024)  # 接收数据的字节数
            if len(date) == 0:
                break
            print(date.decode('utf8'))
        except ConnectionAbortedError:
            sock.close()
            break


# 客户端:
import socket

# 创建对象
client = socket.socket()
# 连接服务器(ip地址与port端口号)
client.connect(('127.0.0.1', 8090))
# 循环交互
while True:
    # 数据交互(接收与发送数据)
    date = client.recv(1024)
    print(date.decode('utf8'))
    # 获得输入的数据
    info = input('请输入信息>>>:').strip()
    client.send(info.encode('utf8'))
复制代码
  • 黏包问题:传输数据时由于不确定接收数据的字节数,因为传输数据时是似流水一样,所以会在接收数据时将数据归到一起,导致黏包问题
复制代码
服务端:

import socket

# 产生一个服务端对象
server = socket.socket()
# 获得对方ip地址与端口
server.bind(('127.0.0.1', 8090))
server.listen(8)
sock, addr = server.accept()

print(sock.recv(1024))  # b'hhahahhahciciiciifkkjjjkkkk'
print(sock.recv(1024))  # b''
print(sock.recv(1024))  # b''

客户端:

import socket

# 获得客户端对象
client = socket.socket()
# 获得对方ip地址与端口
client.connect(('127.0.0.1', 8090))


# 输出数据
client.send(b'hhahahhah')
client.send(b'ciciiciif')
client.send(b'kkjjjkkkk')
复制代码
  • 黏包问题解决办法

   1.解决办法一:获得对方输出数据的字节数

复制代码
服务端:

import socket

# 产生一个服务端对象
server = socket.socket()
# 获得对方ip地址与端口
server.bind(('127.0.0.1', 8090))
server.listen(8)
sock, addr = server.accept()

print(sock.recv(9))  # b'hhahahhah'
print(sock.recv(9))  # b'ciciiciif'
print(sock.recv(9))  # b'kkjjjkkkk'

客户端:

import socket

# 获得客户端对象
client = socket.socket()
# 获得对方ip地址与端口
client.connect(('127.0.0.1', 8090))
print(len('hhahahhah'))   # 9

# 输出数据
client.send(b'hhahahhah')
client.send(b'ciciiciif')
client.send(b'kkjjjkkkk')
复制代码

   2.解决办法二:由于无法确定对方输出的字节数,所以采用struct模块对数据进行固定长度数据打包

     2.1  struct模块:将不确定的数据的字节数打包成统一字节数(struct.pack())

         解包:将打包成统一字节数的 数据还原原本的数据字节数(struct.unpack)

       注:struct模块对数据量特别大的数据无法进行打包

复制代码
import struct

info = '今天天气热的让人发慌'
print(len(info))    # 10
res = struct.pack('i', len(info))
print(len(res))     # 4
res1 = struct.unpack('i', res)
print(res1[0])      # 10
info_dict = {
'name': '索尼',
'price': 5800,
}
# 字典长度
print(len(info_dict)) # 2
# 进行打包处理
res = struct.pack('i', len(info_dict))
print(len(res)) # 4
# 解包处理
res1 = struct.unpack('i', res)
print(res1) # (2,)
print(res1[0]) # 2
复制代码

    2.2 采用struct模块解决黏包问题

      思路:

        传输数据

        1.先将真实数据的长度制作成固定长度 4

        2.先发送固定长度的报头

        3.再发送真实数据

        接收数据

        1.先接收固定长度的报头 4

        2.再根据报头解压出真实长度

        3.根据真实长度接收即可

复制代码
服务端:

import os
import struct
import socket
import json

print(os.path.getsize(r'D:\视频\沉香如屑.mp4'))   # 729983

# 创建服务端对象
server = socket.socket()
# 获得对方ip地址及端口
server.bind(('127.0.0.1', 8090))
server.listen(8)
sock, addr = server.accept()
# 视频信息字典
info_dict = {
    'video_name': '沉香如屑',
    'video_content': '如屑',
    'video_size': 729983
}
# 字典序列化为字符串
json_dict = json.dumps(info_dict)
# 查看长度
json_dict_len = len(json_dict.encode('utf8'))
# 对信息字典进行打包
dict_len = struct.pack('i', json_dict_len)
# 发送打包的字典数据
sock.send(dict_len)
# 发送真实的字典数据
sock.send(json_dict.encode('utf8'))
# 发送视频数据
with open(r'D:\视频\沉香如屑.mp4', 'rb') as f:
    for line in f:
        sock.send(line)

# 客户端
import socket
import json
import struct

# 从客户端下载视频# 获得客户端对象
client = socket.socket()
# 获得读取的ip地址与端口
client.connect(('127.0.0.1', 8090))

# 接收固定的长度的信息字典
dict_len = client.recv(4)
# 解包固定的长度的信息字典
json_dict_len = struct.unpack('i', dict_len)[0]
# 获得真实的字典长度
json_dict = client.recv(json_dict_len)
# 反序列化字典
info_dict = json.loads(json_dict)
print(info_dict)           # {'video_name': '沉香如屑', 'video_content': '如屑', 'video_size': 729983}# 5.从数据字典中获取真实数据的各项信息
total_size = info_dict.get('video_size')
video_size = 0
with open(r'%s' % r'D:\照片\沉香如屑.mp4', 'wb') as f:
    while video_size < total_size:
        data = client.recv(1024)
        f.write(data)
        video_size += len(data)
    print('文件下载完毕')        # 文件下载完毕  
复制代码
 posted on   拾荒菇凉  阅读(84)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示