• 网络编程


    网络协议:

    TCP(Transmission Control Protocol)可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。

      使用TCP的应用:Web浏览器;电子邮件、文件传输程序。

    UDP(User Datagram Protocol)不可靠的、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文,尽最大努力服务,无拥塞控制。

             使用UDP的应用:域名系统 (DNS);视频流;IP语音(VoIP)。

    三次握手(一定是client先发起请求):

    • a 客户端发起请求连接服务器
    • b 服务器返回 : 接收到请求,并要求连接客户端
    • c 客户端回复 : 可以连接

    四次挥手(谁先发起断开连接的请求都可以):

    • a 客户端发起断开连接的请求:意思是: 我想和你断开连接,我没有数据要继续发送了,但是如果你有数据需要发送,我可以继续接收
    • b 服务器回复 : 我接收到你的请求了
    • c 服务器发送 : 我已经准备好断开连接了
    • d 客户端回复 : 收到你的信息,断开连接
     

    架构:

    1 cs(client / server)架构:客户端与用户端架构.    客户端泛指用户端的EXE,需要用户实现安装相应的客户端(app之类).对电脑操作系统依赖较大   优势:发挥pc端的性能

    2 bs(Browser与Server),中文意思:浏览器端与服务器端架构,这种架构是从用户层面来划分的。统一了用户接口

      Browser浏览器,其实也是一种Client客户端,只是这个客户端不需要大家去安装什么应用程序,只需在浏览器上通过HTTP请求服务器端相关的资源(网页资源),客户端Browser               浏览器就能进行增删改查。

    示例小程序:

    import socket  # 引入socket模块
    slicent = socket.socket()  # 创建套连接
    slicent.bind(('192.168.13.58', 8000))  # 创建端口
    slicent.listen(5)  # 最大排队数5
    conn, addr = slicent.accept()  # 等待客户端连接  会有阻塞
    data = conn.recv(1024)   #接收客户端发送来的消息
    print(data.decode("utf8"))#解码打印
    conn.send(b"ok")  #给客户端回复
    slicent.close()
    服务端
    import socket
    server = socket.socket()  # 创建套接字
    server.connect(("192.168.13.58", 8000))  # 连接服务端
    neirong = input("请输入你想说的话:")
    server.send(neirong.encode("utf8"))  #发送给服务端内容
    data = server.recv(1024)  #接收服务端发送来的消息
    print(data.decode())  #打印消息
    server.close() #关闭套连接
    客户端

     

    struct模块:

    import struct
    
    res = struct.pack("i", 123456)  #"i"表示int,后面输入内容只能是int类型,四字节表示 "q"表示long,长整数类型,8字节 编码压包  
    
    print(res)  #b'@xe2x01x00'
    print(len(res))# 4   内容长度压缩到4个字节
    
    
    obj = struct.unpack("i", res)  #解码解包
    print(obj)   # (123456,) 返回的是元组
    print(obj[0])  #123456  取到压缩的内容

    subprocess模块:python中可以执行终端的命令

    import subprocess
    
    res=subprocess.Popen("dir",
                         shell=True,
                         stderr=subprocess.PIPE,
                         stdout=subprocess.PIPE)  
    
    
    print(res.stdout.read().decode("gbk"))

    模拟ssh:

    import socket,subprocess  # 引入socket模块
    slicent = socket.socket()  # 创建套连接
    slicent.bind(('192.168.13.58', 8000))  # 创建端口
    slicent.listen(5)  # 最大排队数5
    
    while 1: #循环建立连接
        print("server is waiting....")
        conn, addr = slicent.accept()  # 等待客户端连接  会有阻塞
    
        while 1:  #循环接受信息
            try:
                cmd= conn.recv(1024).decode("utf8")  #接收客户端发送来的消息
                if cmd == 'exit':  #如果收到的信息是exit 退出本层循环
                    break
                res=subprocess.Popen(cmd,shell=True,stderr=subprocess.PIPE,stdout=subprocess.PIPE)
    
                err=res.stderr.read() #根据给的指令在终端执行 反馈的结果有错误
                out=res.stdout.read()#根据给的指令在终端执行 反馈的结果(正常)
                print("err相应内容",err.decode("gbk"))
                print("out相应内容",out.decode("gbk"))
                if err:#如果有错误
                    import struct
                    header_pack=struct.pack("i",len(err))  #压缩打包err的长度
                    conn.send(header_pack)  #给客户端回复错误字节长度
                    conn.send(err)
    
                else:#如果指令没有错误
                    import struct
                    header_pack=struct.pack("i",len(out)) ##构建报头
                    conn.send(header_pack)  #发送报头
                    conn.send(out)   #发送数据  因为数据为底层的gbk编码 所以不用再次编码
    
            except Exception as e: #异常退出
                break
        conn.close()#关闭本次套接字
    服务端
    import socket,struct
    server = socket.socket()  # 创建套接字
    server.connect(("192.168.13.58", 8000))  # 连接服务端
    while 1:  #循环输入
        cmd = input("请输入命令:")  #给服务端发送想要其执行的指令 例如:dir  ipconfig  ipconfig /all
        if not cmd:continue
        elif cmd =='exit':
            break
        server.send(cmd.encode("utf8"))  #发送给服务端要执行的命令
        data_l = server.recv(4)  #接收服务端发送来的消息的长度
        data_length=struct.unpack("i",data_l)[0]#解包长度
    
        recv_data_length=0  #设定传过来的内容长度
        recv_data=b""       #设定传过来的内容
        while recv_data_length<data_length: #当前传过来的内容长度小于传过来的内容的总长度
            data=server.recv(1024)  #每次接收1024个字节
            recv_data_length+=len(data)  #传过来内容长度
            recv_data+=data#传过来的内容
        print(data.decode('gbk'))  #打印消息
    server.close() #关闭套连接
    客户端

    黏包:

    简单来说就是客户端与服务端存在缓存区,连续发送的文件在缓存区可能被打包成一个文件传到另一服务器端,数据堆叠到一起.获取不到自己想要的内容,引入了struct模块来解决这个问题

     

    文件上传:

    import socket
    import hashlib
    import os
    import json
    import struct
    se = socket.socket()
    se.bind(('192.168.13.58', 8001))
    se.listen(5)
    while True:
        print("等待连接....")
        conn, addr = se.accept()
    
        file_info_length_pack = conn.recv(4)  # 接收json的打包长度
        file_info_length = struct.unpack("i", file_info_length_pack)[0]  # 解包长度
        # 接收json字符串
        file_info_json = conn.recv(file_info_length).decode('utf8')
        file_info = json.loads(file_info_json)
    
        action = file_info.get("action")
        filename = file_info.get("filename")
        file_size = file_info.get("file_size")
    
        # 循环接收文件
        md5 = hashlib.md5()
        with open("put " + filename, "wb")as f:
            recv_data_length = 0
            data = b""
            while recv_data_length < file_size:
                data = conn.recv(1024)
                recv_data_length += len(data)
                f.write(data)
                md5.update(data)
                print("文件总大小", file_size, "当前进度", recv_data_length)
    
        print("接收完成")
        conn.send(b"ok")
        print(md5.hexdigest())
        md5_value = md5.hexdigest()
        client_md5=conn.recv(1024).decode("utf8")
        if md5_value==client_md5:
            conn.send(b"203")
        else:
            conn.send(b"204")
    服务端
    import socket
    import os
    import json
    import hashlib
    import struct
    kh = socket.socket()
    kh.connect(("192.168.13.58", 8001))
    
    while True:
        cmd = input("请输入指令:")  # 格式 put 111.jpg
        action, filename = cmd.strip().split(" ")  # 分解输入内容action=put filiname=111.jpg
        file_size = os.path.getsize(filename)  # 计算文件大小
    
        file_info = {
            "action": action,
            "filename": filename,
            "file_size": file_size}  # 创建字典 把需要的内容一一对应
        file_size_json = json.dumps(file_info).encode("utf-8")  # json规范化
        ret = struct.pack("i", len(file_size_json))  # 创建报头并编码
        kh.send(ret)  # 发送报头
        kh.send(file_size_json)  # 发送file_size_json字节串
    
        md5 = hashlib.md5()  # md5摘要
        with open(filename, mode="rb")as f:  # 上传文件数据
            for line in f:
                kh.send(line)
                md5.update(line)
    客户端

    补充:

     网络编程: 1我的电脑有网卡,网卡里面有mac地址  2插上网线,路由器或者交换机里面的DHCP给我自动分配IP地址.

    IP:IPv4:192.168.13.58    IPv6:255.255.255.255.13.58

    子网掩码:  255.255.255.0

    网关IP:192.168.13.1

    局域网:  arp协议   广播 单播  广播风暴   城域网  广域网

    DNS:  域名与IP的对应关系在哪里?  windows: C:WindowsSystem32driversetchosts           Linux/Mac电脑:    /etc/hosts 

    DNS服务器,全球顶级DNS服务器就13个     baidu.com  123.125.115.110

    总结:

    1. DHCP,自动位局域网内容电脑分配IP。

    2. 网关,路由器中连接交换机的口。

    3. IP,4个点分的十进制表示 192.11.111.11

    4. 子网掩码

          IP: 192.168.13.99
    掩码:255.255.255.0

    将挡住的IP位数作为网段。 未挡住的部分作为可变的值。
    端口:端口是为了将电脑上的不同程序进行分隔,IP 是为了寻找电脑的地址,端口是为了寻找程序的地址.
       MySQL是软件,帮助我们在硬盘上进行文件操作,默认端口:3306
       Redis是一个软件,帮助我们在内存里进行数据操作,默认端口:6379
       一般网站端口是80,或者443
       范围:1-65535(1-1024不可用)默认潜规则:8000,8001...


    OSI 7层模型: 应用层->表示层->会话层->传输层->网络层->数据链接层->物理层

          四层            五层                七层
       
    生产数据:
      应用层:使用软件,打开软件或者网站
      表示层:看到数据 ,如图片视频
      会话层:保持登录或链接状态, 应用偷带一些其他数据,令牌
    传输层:TCP/UDP TCP:面向连接,消息可靠,面向流,无消息保护边界 UDP:面向无连接,消息不可靠,面向包的,有消息保护边界.
    网络层:IP
    数据链接层:MAC
    物理层:发送电信号


     

  • 相关阅读:
    获取设备型号
    笔记
    福大软工 · 最终作业
    福大软工 · 第十二次作业
    Beta 冲刺(7/7)
    Beta 冲刺(6/7)
    Beta 冲刺(5/7)
    Beta 冲刺(4/7)
    Beta 冲刺(3/7)
    Beta 冲刺(2/7)
  • 原文地址:https://www.cnblogs.com/lingcai/p/9594529.html
Copyright © 2020-2023  润新知