• 网络编程扩展


    Day38网络编程扩展

    1、传输层

    PORT协议

    TCP协议 与UDP协议
    规定了数据传输所遵循的规则
    数据传输能够遵循的协议有很多 TCP和UDP只是比较常见的两个

    1.1、TCP协议

    三次握手:建立双向通道
    洪水攻击:就是同时让大量的客户端朝服务端发送建立TCP连接请求

    在这里插入图片描述

    四次挥手:断开双向通道,中间两部不能合并(需要检查的时间停顿,检查是否还有数据没有发送完)

    在这里插入图片描述

    基于TCP传输非常安全 因为有双向通道

    • 基于TCP传输数据,数据容易丢失!,不容易丢失的原因在于二次确认机制
    • 每次发送数据都需要返回确认消息 否则在一定时间就会反复发送

    TCP类似于打电话:你一句 我一句 有来有往
    UDP 类似于发短信:只要发送了 不管别人看没看到也不管回不回复

    2、应用层

    主要取决于程序员自己采用什么策略与协议
    常见的协议有:HTTP HTTPS FTP

    3、socket 套接字

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

    • 套接字家族的名字:AF_UNIX

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

    • 套接字家族的名字:AF_INET

    服务端

    import socket
    
    # 创建一个socket 对象
    server = socket.socket()
    # 绑定一个固定的地址(ip\port)
    # 127.0.0.1 为本地回环地址(只允许自己的机器访问)
    server.bind(('127.0.0.1', 8080))
    # 半连接池(暂且忽略)
    server.listen(5)
    # 准备就绪 等待客户端 来访问(开业,等待接客)
    sock, address = server.accept()
    # sock 是双向通道 address是客户端地址
    print(sock, address)
    # 数据交互
    # 朝客户端发送数据
    sock.send(b'hell big sb')
    # 接收 客户端发送的数据 1024bytes
    data = sock.recv(1024)
    
    print(data)
    #
    # 断开连接
    sock.close()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    客户端

    import socket
    # 产生一个socke对象
    client = socket.socket()
    #连接服务器 (拼接服务端的IP和port)
    client.connect(('127.0.0.1',8080))
    #数据交互
    #接收服务端 发送的数据
    data = client.recv(1024)
    #打印
    print(data)
    # 朝服务端发送数据
    client.send(b'hello small sb')
    # 关闭
    client.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3.1、代码优化

    消息自定义
    利用 input 接收用户数据

    循环通信
    给数据交互环节添加循环即可

    循环通信
    给数据交互环节添加循环即可

    服务端能够持续提高服务
    不会因为客户端 断开连接而报错
    异常捕获 一旦客户端断开连接 服务端结束通信循环 遇到连接处等待

    服务端

    import socket
    import json
    
    # 创建一个socket 对象
    server = socket.socket()
    # 绑定一个固定的地址(ip\port)
    # 127.0.0.1 为本地回环地址(只允许自己的机器访问)
    server.bind(('127.0.0.1', 8080))
    # 半连接池(暂且忽略)
    server.listen(5)
    # 准备就绪 等待客户端 来访问(开业,等待接客)
    #添加循环 让服务端 每次结束客户端连接接触都能回归为等待访问的状态
    while True :
        sock, address = server.accept()
        # sock 是双向通道 address是客户端地址
        print(sock, address)
        # 数据交互
        # 朝客户端发送数据
        # 添加循环 让服务端 能够自定义返回的数据
        while True:
            try:
                sent_data=input('请输入发送的数据>>>').strip()
                if len(sent_data)==0:
                    print('消息不能为空')
                    continue
                sent_data=bytes(sent_data,'utf')
                sock.send(sent_data)
                # 接收 客户端发送的数据 1024bytes
                data = sock.recv(1024)
                data=str(data,'utf')
                print(data)
            #当客户端断开过后 捕获异常
            except Exception:
                break
    #
    # 断开连接
    sock.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    客户端

    import socket
    # 产生一个socke对象
    client = socket.socket()
    #连接服务器 (拼接服务端的IP和port)
    client.connect(('127.0.0.1',8080))
    #数据交互
    #接收服务端 发送的数据
    #添加循环 能够让客户端 重复的发送数据
    while True:
        data = client.recv(1024)
        #打印
        data=str(data,'utf')
        print(data)
        # 朝服务端发送数据
        sent_data=input('请输入要传入的数据>>>').strip()
        sent_data=bytes(sent_data,'utf')
        client.send(sent_data)
    
    # 关闭
    client.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3.2、半连接池

    server.listen(5) #参数 5 表示 等待访问的客户端 数 超过这个数 那么就会使那个客户端报错
    主要为了做缓冲 避免太多无效等待
    
    • 1
    • 2

    3.3、黏包问题

    TCP特性
    流逝协议:所有的数据类似于水流 连接在一起的
    数据量很小 并且时间间隔很多 那么就会自动组织到一起

    recv
    我们不知道即将要接收的数据量很大 如果 知道的话 不会产生也不会产生黏包

    通过struct

    import struct
    
    info = '你好啊 大帅比'
    print(len(info))
    # 将数据原本的长度打包
    res = struct.pack('i', len(info))
    # 打包之后的长度为4
    print(len(res))
    # 将打包之后 固定长度为 4的数据拆包
    ret = struct.unpack('i', res)
    # 又得到了原本数据的长度
    print(ret[0])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    struct模块 无论数据长度 是多少 都可以帮你打包成固定长度
    然后基于该长度 还可以反向解析出真实长度

    3.4、实操

    服务端

    import socket
    import json
    
    # 创建一个socket 对象
    import struct
    
    server = socket.socket()
    # 绑定一个固定的地址(ip\port)
    # 127.0.0.1 为本地回环地址(只允许自己的机器访问)
    server.bind(('127.0.0.1', 8080))
    # 半连接池(暂且忽略)
    server.listen(5)
    # 准备就绪 等待客户端 来访问(开业,等待接客)
    # 添加循环 让服务端 每次结束客户端连接接触都能回归为等待访问的状态
    while True:
        sock, address = server.accept()
        # sock 是双向通道 address是客户端地址
        print(sock, address)
        # 数据交互
        # 朝客户端发送数据
        # 添加循环 让服务端 能够自定义返回的数据
        while True:
            try:
                sent_data = input('请输入发送的数据>>>').strip()
                if len(sent_data) == 0:
                    print('消息不能为空')
                    continue
                # 将获取的数据 转为bytes类型
                sent_data = bytes(sent_data, 'utf')
                # 计算字节个数
                res_w = len(sent_data)
                # 然后进行打包
                res_w = struct.pack('i', res_w)
                # 将打包后的数据发送过去
                sock.send(res_w)
                # 再将真正的数据发送过去
                sock.send(sent_data)
                # 接收 客户端发送的数据
                #首先获取 打包后的 数据
                data = sock.recv(4)
                # 将打包后的数据解包获取真实数据字节数
                data = struct.unpack('i', data)[0]
                #获取真实数据
                b_data = sock.recv(data)
                #解码
                data = str(b_data, 'utf')
                # 打印
                print(data)
            # 当客户端断开过后 捕获异常
            except Exception:
                break
    #
    # 断开连接
    sock.close()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    客户端

    import socket
    import struct
    
    # 产生一个socke对象
    client = socket.socket()
    # 连接服务器 (拼接服务端的IP和port)
    client.connect(('127.0.0.1', 8080))
    # 数据交互
    # 接收服务端 发送的数据
    # 添加循环 能够让客户端 重复的发送数据
    while True:
        #获取真实数据长度打包后的数据
        res = client.recv(4)
        #数据解包获取真实的数据长度
        res_r = struct.unpack('i', res)[0]
        # 通过真实数据长度 获取真实数
        data = client.recv(res_r)
        # 打印
        #解码
        data = str(data, 'utf')
        print(data)
        # 朝服务端发送数据
        sent_data = input('请输入要传入的数据>>>').strip()
        #编码计算 数据长度
        sent_data = bytes(sent_data, 'utf')
        res_w = len(sent_data)
        #将数据长度打包
        res_w = struct.pack('i', res_w)
        # sent_res = bytes(res_w, 'utf')
        # 发送 输出长度打包后的数据
        client.send(res_w)
        #发送真实数据
        client.send(sent_data)
    
    # 关闭
    client.close()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    作业

    服务器

    import socket
    import struct
    import json
    import os
    
    # 创建一个socket 对象
    import struct
    
    server = socket.socket()
    
    # 绑定一个固定的地址 本地回环地址(ip/port)
    server.bind(('127.0.0.1', 8080))
    # 半连接池
    server.listen(5)
    
    while True:
        # 准备就绪 等待客户端访问阶段
        sock, address = server.accept()
        # 是双向通道 address是客户端地址
        print(sock, address)
        # 数据交互
        while True:
            try:
                picture_address = r'C:\Users\82576\Desktop\jason.mp4'
                jason_dict = {'address': picture_address,
                              'png_number': os.path.getsize(picture_address)}
                json_dict = json.dumps(jason_dict)
                b_dict = bytes(json_dict, 'utf')
                dict_bytes_number = len(b_dict)
                res_w = struct.pack('i', dict_bytes_number)
                # 发送字典报头
                sock.send(res_w)
                # 发送字典
                sock.send(b_dict)
                #发送真实数据
                with open(r'%s'%picture_address,'rb')as p_w:
                    sock.send(p_w.read())
    
            except Exception:
                break
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    客户端

    import socket
    import struct
    import json
    
    # 产生一个socket对象
    client = socket.socket()
    # 连接服务器 (拼接服务端ip和port)
    client.connect(('127.0.0.1', 8080))
    
    # 获取字典的抱头
    res_dict = client.recv(4)
    # 解包字典报头
    new_res_dict = struct.unpack('i', res_dict)[0]
    # 获取真实的字典
    b_jason_dict = client.recv(new_res_dict)
    # 反序列化 解码
    jason_dict = json.loads(b_jason_dict)
    # 获取真实数据的报头
    png_res = jason_dict.get('png_number')
    # 获取真实数据
    jason_png = client.recv(png_res)
    with open('jason.mp4', 'wb')as jason_w:
        jason_w.write(jason_png)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
  • 相关阅读:
    泛型的类型擦除
    java spring cloud 企业电子招标采购系统源码:营造全面规范安全的电子招投标环境,促进招投标市场健康可持续发展
    (附源码)小程序 智能养老系统平台 毕业设计 170900
    游戏开发最佳10个工具与技术方案
    2017 黑马 C++ 教学视频
    DRM全解析 —— ADD_FB2(0)
    驱动开发,IO多路复用(select,poll,epoll三种实现方式的比较)
    做外贸必知——你还不知道外贸拼箱技巧吗
    SWT/ANR问题--Deadlock
    windows 安装cuda 11.2过程记录
  • 原文地址:https://blog.csdn.net/weixin_71967396/article/details/126187048