网络编程(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'))   
      
posted @ 2020-03-16 16:06  搁浅Lee  阅读(269)  评论(0编辑  收藏  举报