欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

网络编程(1)

程序员文章站 2022-03-10 12:30:42
概念 局域网 同一局域网内的机器由交换机负责通信。 交换机只识别mac地址,交换机可以完成广播、单播、组播。 arp协议 :通过一台机器的IP地址获取到它的mac地址,用到交换机的广播和单播。 _一台计算机想向同一局域网内的另一个计算机通信必须通过交换机,先向交换机发送自己的IP和mac地址,交换机 ......

概念

局域网

  • 同一局域网内的机器由交换机负责通信。
  • 交换机只识别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'))