zoukankan      html  css  js  c++  java
  • 桐花万里python路-高级篇-网络编程

    • CS架构
      • 客户端 client
      • 服务端 server
    • 网络协议
    • TCP/IP 网络通讯协议 Transmission Control Protocol/Internet Protocol
      • 互联网协议分为osi七层或tcp/ip五层或tcp/ip四层
      • 应用层,表示层,会话层
      • 传输层 
        • 建立端口到端口的通信
        • 端口范围0-65535,0-1023为系统占用端口
        • 传输层有两种协议,TCP(可靠传输)和UDP(不可靠传输)
          • TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会超过IP数据包的长度,以确保单个TCP数据包不必再分割
          • 只要不得到确认,就重新发送数据报,直到得到对方的确认为止
        • TCP协议虽然安全性很高,但是网络开销大,而UDP协议虽然没有提供安全机制,但是网络开销小,在现在这个网络安全已经相对较高的情况下,为了保证传输的速率,我们一般还是会优先考虑UDP协议!
      • 网络层
        • 网络地址,用来区分不同的广播域/子网
        • IP协议 规定网络地址的协议叫ip协议,它定义的地址称之为ip地址。ipv4,ipv6
        • 子网掩码 表示子网络特征的一个参数,将某个IP地址划分成网络地址和主机地址两部分。网络部分全部为1,主机部分全部为0
        • IP地址分类
          1. A类IP地址:一个A类IP地址由1字节的网络地址和3字节主机地址组成,网络地址的最高位必须是“0”, 地址范围从1.0.0.0 到126.0.0.0。可用的A类网络有126个,每个网络能容纳1亿多个主机。
          2. B类IP地址:一个B类IP地址由2个字节的网络地址和2个字节的主机地址组成,网络地址的最高位必须是“10”,地址范围从128.0.0.0到191.255.255.255。可用的B类网络有16382个,每个网络能容纳6万多个主机 。
          3. C类IP地址:一个C类IP地址由3字节的网络地址和1字节的主机地址组成,网络地址的最高位必须是“110”。范围从192.0.0.0到223.255.255.255。C类网络可达209万余个,每个网络能容纳254个主机。
          4. D类地址用于多点广播(Multicast): D类IP地址第一个字节以“lll0”开始,它是一个专门保留的地址。它并不指向特定的网络,目前这一类地址被用在多点广播(Multicast)中。多点广播地址用来一次寻址一组计算机,它标识共享同一协议的一组计算机。
          5. E类IP地址 以“llll0”开始,为将来使用保留
        • IP报文
          • 所有的TCP,UDP,IMCP,IGCP的数据都以IP数据格式传输
          • TCP是一个可靠的协议,而UDP就没有那么可靠的区别
          • 协议头
        • ARP协议 广播的方式发送数据包,获取目标主机的mac地址
      • 网络接口层:数据链路层
        • 定义了电信号的分组方式
        • 以太网协议ethernet
          • 一组电信号构成一个数据包,叫做‘帧’
          • 每一数据帧分成:报头head和数据data两部分
          • head固定18个字节
            1. 发送者 / 源地址 6字节
            2. 接受者 / 目标地址 6字节
            3. 数据类型 6字节
          • data 数据包的具体内容 最短46字节,最长1500字节
        • mac地址
        • 广播发送方式 同一网络内的两台主机,通过arp协议获取另外一台主机的mac地址 
      • 网络接口层:物理层
        • 主要是基于电器特性发送高低电压(电信号),高电压对应数字1,低电压对应数字0
    • Socket  是一组应用层与TCP/IP协议族通信的中间软件抽象层的接口。通过代码封装了tcp/ip协议层的各种数据封装、数据发送、接收等
        • 工作模式
      • 套接字方法 
        • 语法规范
          socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
        • family 
          • socket.AF_UNIX 本机进程间通讯
          • socket.AF_INET AF_INET6被用于ipv6
        • type
          • socket.SOCK_STREAM #for tcp
          • socket.SOCK_DGRAM #for udp
          • socket.SOCK_RAW #原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文
          • socket.SOCK_RDM #是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
        • 服务端方法
          • s.bind() 绑定(主机,端口号)到套接字
          • s.listen() 开始TCP监听
          • s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来
        • 客户端方法
          • s.connect() 主动初始化TCP服务器连接
          • s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
        • 公用方法
          • s.recv() 接收数据
          • s.send() 发送数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完,可后面通过实例解释)
          • s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
          • s.recvfrom() Receive data from the socket. The return value is a pair (bytes, address)
          • s.getpeername() 连接到当前套接字的远端的地址
          • s.close() 关闭套接字
          • socket.setblocking(flag) #True or False,设置socket为非阻塞模式,以后讲io异步时会用
          • socket.getaddrinfo(host, port, family=0, type=0, proto=0, flags=0) 返回远程主机的地址信息,例子 socket.getaddrinfo('luffycity.com',80)
          • socket.getfqdn() 拿到本机的主机名
          • socket.gethostbyname() 通过域名解析ip地址
    • 粘包 只存在于TCP中,socket缓冲区导致的,多次发送的数据包粘到一起
      • 接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的
      • 解决方案
      • 服务端在处理数据的时候
        • 先将数据总长计算出
        • 先整理成报头字典,包含内容长度
        • 发送报文长度
        • 再发送报头
        • 最后发送具体数据
          import struct
          import json
          import socket
          import subprocess
          import settings
          
          serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
          serv.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
          serv.bind((settings.HOST, settings.TCPPORT))
          
          serv.listen(5)
          print("服务器已启动")
          while True:
              conn, addr = serv.accept()
              print("客户端:",conn)
              while True:
                  content = conn.recv(1024)
                  ret = content.decode("utf-8")
                  print("recv:%s" % (ret))
                  res = subprocess.Popen(ret,shell=True,stdout=subprocess.PIPE,stdin=subprocess.PIPE,stderr=subprocess.PIPE)
                  stderr = res.stderr.read()
                  stdout = res.stdout.read()
                  # stdout = content
                  print("res length", len(stdout))
                  resp = bytes(json.dumps({'content-length':len(stdout)}),encoding="utf-8")
          
                  conn.send(struct.pack('i',len(resp))) # 发送报头长度
                  conn.send(resp)     # 发送报头
                  conn.send(stdout)   # 发送具体数据 
          View Code
      • 客户端接受数据
        • 先接受固定长度的报头数据得到报头长度
        • 再按报头长度接受报头,解析报头得到具体内容长度
        • 循环接收具体内容到缓冲区,拼接缓冲区数据
        • 最后再将接收的数据转码
          import struct
          import json
          import socket
          import settings
          
          cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
          
          cli.connect((settings.HOST, settings.TCPPORT))
          
          while True:
              echo = input(":>>").strip()
          
              cli.send(echo.encode('utf-8'))
              if len(echo) == 0:
                  continue
              if echo == 'q':
                  break
          
              head = cli.recv(4)  # 接收报头长度
              header_bytes = struct.unpack('i', head)  # 解出报头的长度
              head_info = cli.recv(header_bytes[0])   # 接收报头
              header = json.loads(head_info)          # 解析报头
              print(header)
              content_length = header.get('content-length')
              print(content_length, type(content_length))
              recv_length = 0
              content = b'' # 数据缓存区
              while recv_length < content_length:
                  if recv_length >= content_length:
                      break
                  _content = cli.recv(settings.BUFFSIZE)  # 循环接收数据
                  content += _content
                  recv_length += settings.BUFFSIZE
              #
              print(content_length, ' = ', len(content), content.decode('gbk')) # 转码接收的数据
          View Code
    • 其他
  • 相关阅读:
    Cookie中文乱码问题
    [转]Resolving kernel symbols
    [转]Blocking Code Injection on iOS and OS X
    [转]About the security content of iOS 8
    [转]iOS: About diagnostic capabilities
    [转]iOS hacking resource collection
    [转]Patching the Mach-o Format the Simple and Easy Way
    [转]Use the IDA and LLDB explore WebCore C + + class inheritance
    [转]Avoiding GDB Signal Noise.
    [转]http://www.russbishop.net/xcode-exception-breakpoints
  • 原文地址:https://www.cnblogs.com/zhujingxiu/p/8352739.html
Copyright © 2011-2022 走看看