• 网络编程(1)


    概念

    局域网

    • 同一局域网内的机器由交换机负责通信。
    • 交换机只识别mac地址,交换机可以完成广播、单播、组播。
    • arp协议:通过一台机器的IP地址获取到它的mac地址,用到交换机的广播和单播。
      一台计算机想向同一局域网内的另一个计算机通信必须通过交换机,先向交换机发送自己的IP和mac地址,交换机通过广播向所有计算机发送信息,只有对应计算机会应答并向交换机发送自己的mac地址,从而实现同一局域网内的通信。

    局域网之间通信

    • 局域网之间通信通过路由器。
    • 路由器可识别IP地址,并且路由器提供网关IP,同一个局域网的所有机器共享一个网关IP。
    • 每个局域网有一个网段,路由器内有路由表,一个网关IP对应一个网段。

    IP地址

    • IPV4:点分十进制(0.0.0.0 - 255.255.255.255)
    • 公网地址:需要申请购买
    • 内网地址:保留字段
      • 192.168.0.0 - 192.168.255.255 学校
      • 172.16.0.0 - 172.31.255.255 学校
      • 10.0.0.0 - 10.255.255.255 公司
    • 127.0.0.1为本地回环地址,通常用于测试。
    • 查看自己的IP地址:ipconfig(Windows)/ifconfig(Mac/Linix)
    • 子网掩码:为一个IP地址,用于判断两台机器在不在同一局域网内,采用二进制相与的方法,当相与结果相同则在同一局域网内。

    网络开发架构

    C/S架构

    • 需要安装才可使用

    • client:客户端,server:服务端

    • 离线可使用,功能更完善,安全性更高

        # 基于tcp
        # server端
        import socket
        sk = socket.socket()
        sk.bind(('127.0.0.1', 5002)) # 5002是端口
        # 打开监听模式
        sk.listen()
        # 建立连接,conn是连接,addr是连接的地址
        conn, addr = sk.accept()
        # 发送信息
        conn.send(b'Hello, I am server')
        # 最多接收1024字节
        msg = conn.recv(1024)
        print(msg)
        print(addr)
        conn.close() # 关闭连接
        sk.close() # 关闭整个服务
        #########################################
        # client端
        import socket
        sk = socket.socket()
        # 建立连接
        sk.connect(('127.0.0.1', 5002))
        # 接收信息
        msg = sk.recv(1024)
        print(msg)
        # 发送信息
        sk.send(b'Hello, I am client')
        sk.close() # 关闭连接
      

    B/S架构

    • 不用安装就可使用
    • browser:浏览器,server:服务端
    • 其中B/S也是C/S架构的一种

    OSI五层协议

    • 应用层:应用程序(python)
    • 传输层:port,udp/tcp,四层路由器,四层交换机
    • 网络层:ipv4/ipv6,路由器,三层交换机
    • 数据链路层:mac,arp协议,网卡,二层交换机
    • 物理层

    tcp和udp

    • tcp:需要建立连接才能通信

      • 占用连接,可靠(信息不会丢失),实时性高
      • 建立连接:三次握手(建立全双工通信
      • 断开连接:四次挥手
    • udp:不需要建立连接就可以通信

      • 不占用连接,不可靠(消息因为网络不稳定丢失)

      • 需要用到.recvfrom(可接收信息和IP)和.sendto(发送信息需附带IP地址)。

        # server端
        # 一服务端对多客户端通信
        # 服务端不用主动退出,由客户端收发消息进行退出
        import socket
        sk = socket.socket(type = socket.SOCK_DGRAM) # 默认参数是tcp,此参数为udp
        sk.bind(('127.0.0.1', 5002))            
        while True:
            # 不能先发送,因为不知道接收端地址信息,只能等待接收,并且必须接收到客户端的地址
            msg_r, addr = sk.recvfrom(1024)
            print(addr)
            print(msg_r.decode('UTF-8'))
            msg_s = input(">>>")
            sk.sendto(msg_s.encode('UTF-8'), addr)
        ################################################
        # client端
        import socket
        sk = socket.socket(type = socket.SOCK_DGRAM)
        # 传入服务端地址
        server = ('127.0.0.1', 5002)
        while True:
            msg_s = input(">>>")
            sk.sendto(msg_s.encode('UTF-8'), server)
            if msg_s == "拜拜": break
            # 接收服务端的信息,由于知道服务端地址所以不需要recvfrom
            msg_r = sk.recv(1024)
            if msg_r.decode('UTF-8') == "拜拜": break
            print(msg_r.decode('UTF-8'))
        
    • 粘包现象

      • 只出现在tcp协议中,因为tcp协议的多条信息之间没有边界,并且有优化算法。
        tcp协议发送数据大小没有上限,当数据过大时会将数据进行拆分,所以多条消息之间没有边界

      • 发送端:两条消息都很短,发送间隔时间也非常短导致。

      • 接收端:多条消息由于没有及时接收,接收端缓存堆在一起导致。

      • 解决办法:设置边界
        自定义协议:发送端统计长度,每次将长度固定为n字节发送

        # server端同时发送两条消息
        msg_s1 = input(">>>")
        msg_s2 =input(">>>")
        lens = str(len(msg_s1)) # 统计msg_s1的长度,ziff传入数据应为str,所以要转成str
        len = lens.zfill(4) # 将收集到的长度大小统一扩至4字节,例如msg_s1长度为6字节,则为0006
        conn.send(len.encode('UTF-8')) # 将长度信息发送出去
        conn.send(msg_s1.encode('UTF-8'))
        conn.send(msg_s2.encode('UTF-8'))
        
        # clien端接收
        len = int(sk.recv(4).decode('UTF-8')) # 接收长度信息
        msg_r1 = sk.recv(len)
        msg_r2 = sk.recv(1024)
        print(msg_r2.decode('UTF-8'))
        print(msg_r1.decode('UTF-8'))
        ###############################################################
        # struct方法
        # server端同时发送两条消息
        msg_s1 = input(">>>")
        msg_s2 =input(">>>")
        lens_byte = struct.pack('i', len(msg_s1)) # 可以将数据转成固定4字节
        conn.send(lens_byte)
        conn.send(msg_s1.encode('UTF-8'))
        conn.send(msg_s2.encode('UTF-8'))
        
        # clien端接收
        lens_byte = sk.recv(4)
        len = struct.unpack('i', lens_byte)[0] # unpack返回值为元组,第一位即为长度信息
        msg_r1 = sk.recv(len)
        msg_r2 = sk.recv(1024)
        print(msg_r1.decode('UTF-8'))
        print(msg_r2.decode('UTF-8'))
  • 相关阅读:
    python idea 利用树莓派做家庭报警系统
    Browserslist: caniuse-lite is outdated. Please run next command `npm update`
    maven项目最外层有个红x,项目其他没有x
    要取消:根据 sitemap 的规则[0],当前页面 [pages/index/index] 将被索引
    MySQL的DATE_FORMAT()用法
    maven项目的java和resources等文件夹不在Java Resources的文件夹里,并且缺少Deployment...
    小程序开发demo及资源
    wx.requestSubscribeMessage 订阅消息
    java获取年月日
    goland 文件头自动注释
  • 原文地址:https://www.cnblogs.com/geqianLee/p/12504508.html
Copyright © 2020-2023  润新知