ip/udp/tcp包 学习
/**
 * 以太网
 */
class Ethernet {
  static readonly size = 14;
  get Destination(): string {
    return [
      this.view.getUint8(0),
      this.view.getUint8(1),
      this.view.getUint8(2),
      this.view.getUint8(3),
      this.view.getUint8(4),
      this.view.getUint8(5),
    ]
      .map((it) => it.toString(16))
      .join(":");
  }
  get Source(): string {
    return [
      this.view.getUint8(6),
      this.view.getUint8(7),
      this.view.getUint8(8),
      this.view.getUint8(9),
      this.view.getUint8(10),
      this.view.getUint8(11),
    ]
      .map((it) => it.toString(16))
      .join(":");
  }
  get Type(): number {
    return this.view.getUint16(12);
  }
  view: DataView;
  constructor(ethernetBytes: number[]) {
    this.view = new DataView(Uint8Array.from(ethernetBytes).buffer);
  }
}
/**
 * 解析IP头
 */
class IP {
  //See also: http://mars.netanya.ac.il/~unesco/cdrom/booklet/HTML/NETWORKING/node020.html
  static readonly size = 20;
  /**
   * ## 版本号
   * - 数据报属于哪个协议版本。
   */
  get Version(): number {
    return this.view.getUint8(0) >> 4;
  }
  set Version(value: number) {
    if (value > 0xf) throw new Error("value 不能超过4-bit(15).");
    this.view.setUint8(0, (value << 4) | this.HeaderLength);
  }
  /**
   * - 标头中32位字的数量(DWORD)
   * - 因为这是4位,所以最大报头长度为15个字(即60个字节)
   * - 标头至少为20个字节,但Option(0 or more words)可能会使它更大
   */
  get HeaderLength(): number {
    return this.view.getUint8(0) & 0xf;
  }
  set HeaderLength(value: number) {
    if (value > 0xf) throw new Error("value 不能超过4-bits.");
    this.view.setUint8(0, value | (this.Version << 4));
  }
  /**
   * ## 服务种类
   * - 包含一个3位优先级字段(今天将被忽略),4个服务位和1个未使用位。
   * - 四个服务位可以是:
        - 1000-最小化延迟
        - 0100-最大化吞吐量
        - 0010-最大化可靠性
        - 0001-最小化金钱成本
   */
  get TypeOfService(): number {
    return this.view.getUint8(1);
  }
  set TypeOfService(value: number) {
    if (value > 0xff) throw new Error("value 不能超过8-bits.");
    this.view.setUint8(1, value);
  }
  /**
   * ## 总长度
   * - 数据报的总长度(以字节为单位)。
   * - 我们知道数据从头开始的位置
   * - 我们通过计算“Total Length-Header Length”知道DATA的大小
   * - Total Length使用(WORD)储存,最多存0xFFFF(65535)字节
   * - 但是物理层可能不允许这么多字节的数据包大小
   * - 因此,IP有时必须对数据包进行分段。
   * - 当IP数据报被分段时,每个分段都被视为一个单独的数据报。
   *    - 它在最终目的地而不是在路由器处重新组装!
   * - 每个片段都有自己的header
   * - 标识号被复制到每个片段中。See also: MF/DF/FragmentOffset
   */
  get TotalLength(): number {
    return this.view.getUint16(2);
  }
  set TotalLength(value: number) {
    if (value > 0xffff) throw new Error("value 不能超过16-bits.");
    this.view.setUint16(2, value);
  }
  /**
   * ## 身份证明
   * - 唯一标识数据报
   * - 通常每次发送数据报时加1。
   * - 数据报的所有片段都包含相同的标识值。
   * - 这使目标主机可以确定哪个片段属于哪个数据报。
   */
  get Identification(): number {
    return this.view.getUint16(4);
  }
  set Identification(value: number) {
    if (value > 0xffff) throw new Error("value 不能超过16-bits.");
    this.view.setUint16(4, value);
  }
  /**
   * ## Don't fragment 不要碎片
   * - 如果为1,则表示“请勿分段”。
   * - 如果IP必须分片数据包并且该位置1,则IP丢弃数据报。
   */
  get DF(): number {
    return (this.view.getUint8(6) >> 6 & 1;
  }
  set DF(value: number) {
    if (value !== 0 && value !== 1) throw new Error("value 只能为1或者0.");
    if (value === this.DF) return;
    this.view.setUint8(6, this.view.getUint8(6) ^ (1 << 6));
  }
  /**
   * ## More Fragment 片段标志
   * - 如果该位为0,则表示这是最后一个片段
   * - IP标头的所有其他字段与第一个数据包相同(校验和除外)
   * - 路由器看到3个单独的数据包。在最终目的地上将数据包传递到上层之前重新组装数据包
   * - 片段标志(MF)0和偏移量(FragmentOffset)0表示数据报未分片
   */
  get MF(): number {
    return (this.view.getUint8(6) >> 5 & 1;
  }
  set MF(value: number) {
    if (value !== 0 && value !== 1) throw new Error("value 只能为1或者0.");
    if (value === this.MF) return;
    this.view.setUint8(6, this.view.getUint8(6) ^ (1 << 5));
  }
  /**
   * ## 碎片偏移
   * - 片段标志(MF)0和偏移量(FragmentOffset)0表示数据报未分片
   * - 片段偏移量以8字节(QWORD)为单位进行测量。这是因为片段偏移字段比总长度字段短3位(并且2^3为8)。
   */
  get FragmentOffset(): number {
    return this.view.getUint16(6) & 0x1fff;
  }
  set FragmentOffset(value: number) {
    if (value > 0x1fff) throw new Error("value 不能超过13-bits.");
    // 删除旧址在设置新值
    this.view.setUint16(6, value | (this.DF << 14) | (this.MF << 13));
  }
  /**
   * ## 生存时间
   * - 路由器上限
   * - 通常设置为32或64。
   * - 每个处理数据报的路由器都会递减,
   * - 当TTL达到0时,路由器将丢弃该数据报。
   */
  get TimeToLive(): number {
    return this.view.getUint8(8);
  }
  set TimeToLive(value: number) {
    if (value > 0xff) throw new Error("value 不能超过8-bits.");
    this.view.setUint8(8, value);
  }
  /**
   * ## 协议
   * - 告诉IP将数据报发送到哪里。
   * - 6表示TCP
   * - 17表示UDP
   */
  get Protocol(): number {
    return this.view.getUint8(9);
  }
  setProtocol(value: number) {
    if (value > 0xff) throw new Error("value 不能超过8-bits.");
    this.view.setUint8(9, value);
  }
  /**
   * ## 标头校验和
   * - 仅覆盖标题,不覆盖数据。
   */
  get HeaderChecksum(): number {
    return this.view.getUint16(10);
  }
  set HeaderChecksum(value: number) {
    if (value > 0xffff) throw new Error("value 不能超过16-bits.");
    this.view.setUint16(10, value);
  }
  updateHeaderChecksum() {
    this.HeaderChecksum = 0;
    let offset = 0;
    const a = [];
    while (offset < this.view.byteLength) {
      a.push(this.view.getUint16(offset));
      offset += 2;
    }
    const v = a.reduce<number>((acc, it) => {
      acc += it;
      if (acc > 0xffff) {
        // 进位
        const leftmost = acc >> 16;
        acc = (acc ^ (leftmost << 16)) + leftmost;
      }
      return acc;
    }, 0);
    this.HeaderChecksum = ~v;
  }
  checkHeaderChecksum(): boolean {
    let offset = 0;
    const a = [];
    while (offset < this.view.byteLength) {
      a.push(this.view.getUint16(offset));
      offset += 2;
    }
    const v = a.reduce<number>((acc, it) => {
      acc += it;
      if (acc > 0xffff) {
        // 进位
        const leftmost = acc >> 16;
        acc = (acc ^ (leftmost << 16)) + leftmost;
      }
      return acc;
    }, 0);
    return 0 === ~v;
  }
  /**
   * 源IP地址
   */
  get Source(): number {
    return this.view.getUint32(12);
  }
  set Source(value: number) {
    if (value > 0xffffffff) throw new Error("value 不能超过32-bits.");
    this.view.setUint32(12, value);
  }
  /**
   * 这只是[Source]的字符串形式
   */
  get SourceString(): string {
    return [
      this.view.getUint8(12),
      this.view.getUint8(13),
      this.view.getUint8(14),
      this.view.getUint8(15),
    ].join(".");
  }
  /**
   * 以字符串的形式设置[Source]
   * @param value 如: "192.168.1.6"
   */
  set SourceString(value: string) {
    const a: string[] = value.split(".");
    if (a.length !== 4)
      throw new Error(`setSourceString value Error: (${value})`);
    const inta: number[] = a.map((it) => {
      const r = parseInt(it, 10);
      if (r > 0xff) throw new Error(`码点(${it})不能超过8-bits.`);
      return r;
    });
    this.view.setUint8(12, inta[0]);
    this.view.setUint8(13, inta[1]);
    this.view.setUint8(14, inta[2]);
    this.view.setUint8(15, inta[3]);
  }
  /**
   * 目的IP地址
   */
  get Destination(): number {
    return this.view.getUint32(16);
  }
  set Destination(value: number) {
    if (value > 0xffffffff) throw new Error("value 不能超过32-bits.");
    this.view.setUint32(16, value);
  }
  /**
   * 这只是[Destination]的字符串形式
   */
  get DestinationString(): string {
    return [
      this.view.getUint8(16),
      this.view.getUint8(17),
      this.view.getUint8(18),
      this.view.getUint8(19),
    ].join(".");
  }
  /**
   * 以字符串的形式设置
   * @param value 如: "192.168.1.6"
   */
  setDestinationString(value: string) {
    const a: string[] = value.split(".");
    if (a.length !== 4)
      throw new Error(`setDestinationString value Error: (${value})`);
    const inta: number[] = a.map((it) => {
      const r = parseInt(it, 10);
      if (r > 0xff) throw new Error(`码点(${it})不能超过8-bits.`);
      return r;
    });
    this.view.setUint8(16, inta[0]);
    this.view.setUint8(17, inta[1]);
    this.view.setUint8(18, inta[2]);
    this.view.setUint8(19, inta[3]);
  }
  view: DataView;
  constructor(ipBytes: number[]) {
    this.view = new DataView(Uint8Array.from(ipBytes).buffer);
  }
  toString(): string {
    return `
0100 .... = Version: ${this.Version}
.... 0101 = Header Length: ${this.HeaderLength * 4} bytes (${this.HeaderLength})
Type Of Service: 0x0${this.TypeOfService.toString(16)}
Total Length: ${this.TotalLength}
Identification: 0x${this.Identification.toString(16)} (${this.Identification})
Df: ${this.DF}
MF: ${this.MF}
Fragment offset: ${this.FragmentOffset}
Time to live: ${this.TimeToLive}
Protocol: ${
      this.Protocol == 6 ? "TCP" : this.Protocol == 17 ? "UDP" : "Other"
    } (${this.Protocol})
Header checksum: 0x${this.HeaderChecksum.toString(16)}
Source: ${this.SourceString}
Destination: ${this.DestinationString}
    `.trim();
  }
}
/**
 * ## User Datagram Protocol 用户数据报协议
 * - UDP是一种简单的无连接协议。它不提供可靠性;它只是将数据发送到IP层
 */
class UDP {
  static readonly size = 8;
  get SourcePort(): number {
    return this.view.getUint16(0);
  }
  set SourcePort(value: number) {
    if (value > 0xffff) throw new Error("value 不能超过16-bits.");
    this.view.setUint16(0, value);
  }
  get DestinationPort(): number {
    return this.view.getUint16(2);
  }
  set DestinationPort(value: number) {
    if (value > 0xffff) throw new Error("value 不能超过16-bits.");
    this.view.setUint16(2, value);
  }
  /**
   * - 长度是报头和数据的字节数
   * - header是8个字节
   * - IP数据报的最大大小为65535字节,IP报头减去20字节===>剩余65515字节用于数据。但是,UDP标头为8个字节,剩下65507个字节用于最大数量的用户数据。(不确定)
   */
  get Length(): number {
    return this.view.getUint16(4);
  }
  set Length(value: number) {
    if (value > 0xffff) throw new Error("value 不能超过16-bits.");
    this.view.setUint16(4, value);
  }
  get Checksum(): number {
    return this.view.getUint16(6);
  }
  set Checksum(value: number) {
    if (value > 0xffff) throw new Error("value 不能超过16-bits.");
    this.view.setUint16(5, value);
  }
  /**
   * 计算校验和
   */
  updateChecksum() {
    this.Checksum = 0;
    const dataSize = this.view.byteLength - UDP.size;
    const byteLength = 20 + (dataSize % 2 !== 0 ? 0 : dataSize);
    const pseudoHeader = new DataView(new ArrayBuffer(byteLength));
    pseudoHeader.setUint32(0, this.ip.Source);
    pseudoHeader.setUint32(4, this.ip.Destination);
    pseudoHeader.setUint16(8, this.ip.Protocol);
    pseudoHeader.setUint16(10, this.Length);
    pseudoHeader.setUint16(12, this.SourcePort);
    pseudoHeader.setUint16(14, this.DestinationPort);
    pseudoHeader.setUint16(16, this.Length);
    pseudoHeader.setUint16(18, this.Checksum);
    if (dataSize % 2 === 0) {
      for (let i = 0; i < dataSize - 1; i++) {
        pseudoHeader.setUint8(20 + i, this.view.getUint8(UDP.size + i));
      }
    }
    let offset = 0;
    const a = [];
    while (offset < pseudoHeader.byteLength) {
      a.push(pseudoHeader.getUint16(offset));
      offset += 2;
    }
    const v = a.reduce<number>((acc, it) => {
      acc += it;
      if (acc > 0xffff) {
        // 进位
        const leftmost = acc >> 16;
        acc = (acc ^ (leftmost << 16)) + leftmost;
      }
      return acc;
    }, 0);
    this.Checksum = ~v;
  }
  view: DataView;
  constructor(public readonly ip: IP, udpBytes: number[]) {
    this.view = new DataView(Uint8Array.from(udpBytes).buffer);
  }
}
/**
 * ## Transmission Control Protocol 传输控制协议
 * - 不可靠的网络上可靠的端到端字节流。
 */
class TCP {
  /**
   * TCP标头必须至少包含20字节(5个字)的固定格式信息以及一个可选部分(该部分始终为4字节的整数倍)
   */
  static readonly size = 20;
  /**
   *
   * - 端口是用于进程间通信的逻辑地址。端口在一台主机内(甚至在一台进程内)提供多个目的地。
   * - 低于256的端口号是“知名”端口,例如:FTP 21,TELNET 23,SMTP 25,HTTP 80,POP3 110。
   * - 低于1024的端口号保留用于系统服务。只允许管理员(例如Unix中的root)分配他们
   * - 用户进程可以使用1024到65535(2 ^ 16-1)之间的端口号,而无需任何特殊许可。
   * - 可以通过组合[SourceIPAddress.PortNumber,DestinationIPAddress.PortNumber]来标识定义通信通道端点的套接字对。
   * - IP号码加端口号构成一个TSAP-传输服务访问点(有时也称为套接字)。
   */
  get SourcePort(): number {
    return this.view.getUint16(0);
  }
  set SourcePort(value: number) {
    if (value > 0xffff) throw new Error("value 不能超过16-bits.");
    this.view.setUint16(0, value);
  }
  get DestinationPort(): number {
    return this.view.getUint16(2);
  }
  set DestinationPort(value: number) {
    if (value > 0xffff) throw new Error("value 不能超过16-bits.");
    this.view.setUint16(2, value);
  }
  /**
   * ## 序列号
   * - 一个32位数字(DWORD)
   * - 数据的每个字节都有编号。
   * - TCP段的序列号是该段中第一个数据字节的ID号
   * - 它不需要从1开始!
   * - 有效序列号的范围是0到4,294,967,295(0x0000,0000-0xFFFF,FFFF)
   */
  get SequenceNumber(): number {
    return this.view.getUint32(4);
  }
  set SequenceNumber(value: number) {
    if (value > 0xffffffff) throw new Error("value 不能超过32-bits.");
    this.view.setUint32(4, value);
  }
  /**
   * ## 确认号
   * - 一个32位数字(DWORD)
   * - 指定发送者期望的下一个字节的编号(而不是正确接收的最后一个字节!)
   * - 通常将数据从接收方发送到发送方
   * - 如果此确认段在特定时间内未到达,则发送方重新传输前一个段(计时器)
   */
  get AcknowledgmentNumber(): number {
    return this.view.getUint32(8);
  }
  set AcknowledgmentNumber(value: number) {
    if (value > 0xffffffff) throw new Error("value 不能超过32-bits.");
    this.view.setUint32(8, value);
  }
  /**
   * TCP标头中的标头长度数(32位)。此信息是必需的,因为标题有时可能超过4个字。仅4位分配给TCP标头长度字段。因此,最长为15个字(60个字节)
   */
  get TCPHeaderLength(): number {
    return this.view.getUint8(12) >> 4;
  }
  set TCPHeaderLength(value: number) {
    if (value > 0xf) throw new Error("value 不能超过4-bits.");
    this.view.setUint8(12, value << 4);
  }
  /**
   * ## Urgent
   * - 紧急指针有效,与当前序列号的字节偏移,在当前序列号处可以找到紧急数据(中断消息)。当中止rlogin或telnet连接或ftp数据传输时,使用紧急模式。
   */
  get URG(): number {
    return this.view.getUint8(13) >> 5 & 1;
  }
  set URG(value: number) {
    if (value !== 0 && value !== 1) throw new Error("value 只能为1或者0.");
    if (value === this.URG) return;
    this.view.setUint8(13, this.view.getUint8(13) ^ (1 << 5));
  }
  /**
   * ## Acknowledgment 确认编号有效
   * - 如果ACK = 0,则此段中没有确认
   */
  get ACK(): number {
    return this.view.getUint8(13) >> 4 & 1;
  }
  set ACK(value: number) {
    if (value !== 0 && value !== 1) throw new Error("value 只能为1或者0.");
    if (value === this.ACK) return;
    this.view.setUint8(13, this.view.getUint8(13) ^ (1 << 4));
  }
  /**
   * ## Push 接收方应尽快将此数据传递给应用程序
   * - 接收方被请求在到达时将数据传递给应用程序,而不是缓冲它。
   */
  get PSH(): number {
    return this.view.getUint8(13) >> 3 & 1;
  }
  set PSH(value: number) {
    if (value !== 0 && value !== 1) throw new Error("value 只能为1或者0.");
    if (value === this.PSH) return;
    this.view.setUint8(13, this.view.getUint8(13) ^ (1 << 3));
  }
  /**
   * ## Reset 重置(关闭)连接。
   */
  get RST(): number {
    return this.view.getUint8(13) >> 2 & 1;
  }
  set RST(value: number) {
    if (value !== 0 && value !== 1) throw new Error("value 只能为1或者0.");
    if (value === this.RST) return;
    this.view.setUint8(13, this.view.getUint8(13) ^ (1 << 2));
  }
  /**
   * ## Syn 同步序列号以开始连接
   */
  get SYN(): number {
    return this.view.getUint8(13) >> 1 & 1;
  }
  set SYN(value: number) {
    if (value !== 0 && value !== 1) throw new Error("value 只能为1或者0.");
    if (value === this.RST) return;
    this.view.setUint8(13, this.view.getUint8(13) ^ (1 << 1));
  }
  /**
   * ## 发送方已完成数据发送
   */
  get FIN(): number {
    return this.view.getUint8(13) & 1;
  }
  set FIN(value: number) {
    if (value !== 0 && value !== 1) throw new Error("value 只能为1或者0.");
    if (value === this.RST) return;
    this.view.setUint8(13, this.view.getUint8(13) ^ 1);
  }
  /**
   * 此字节的发送者愿意接受的数据字节数,从确认字段中指示的字节数开始。窗口大小为0表示已收到直到确认编号1为止的字节,但是此刻接收器无法接受更多数据。稍后,如果接收方准备好接收更多数据,则他发送具有相同确认号和非零窗口大小的段(如果丢失该段,则发送方每隔一定的时间探测接收方)。
   */
  get WindowSize(): number {
    return this.view.getUint16(14);
  }
  set WindowSize(value: number) {
    if (value > 0xffff) throw new Error("value 不能超过16-bits.");
    this.view.setUint16(14, value);
  }
  /**
   * 整个段的16位校验和(加上伪IP标头)。
   */
  get Checksum(): number {
    return this.view.getUint16(16);
  }
  set Checksum(value: number) {
    if (value > 0xffff) throw new Error("value 不能超过16-bits.");
    this.view.setUint16(16, value);
  }
  get UrgentPointer(): number {
    return this.view.getUint16(18);
  }
  set UrgentPointer(value: number) {
    if (value > 0xffff) throw new Error("value 不能超过16-bits.");
    this.view.setUint16(18, value);
  }
  view: DataView;
  constructor(public readonly ip: IP, udpBytes: number[]) {
    this.view = new DataView(Uint8Array.from(udpBytes).buffer);
  }
}
class Data {
  get data(): Uint8Array {
    return new Uint8Array(this.view.buffer);
  }
  set data(value: Uint8Array) {
    this.view = new DataView(value.buffer);
  }
  view: DataView;
  constructor(dataBytes: number[]) {
    this.view = new DataView(Uint8Array.from(dataBytes).buffer);
  }
}
class Packet {
  ethernet: Ethernet;
  ip: IP;
  udp?: UDP;
  tcp?: TCP;
  data: Data;
  #_view!: DataView;
  get view(): DataView {
    for (let i = 0; i < IP.size; i++)
      this.#_view.setUint8(Ethernet.size + i, this.ip.view.getUint8(i));
    if (this.udp)
      for (let i = 0; i < UDP.size; i++)
        this.#_view.setUint8(
          Ethernet.size + IP.size + i,
          this.ip.view.getUint8(i)
        );
    return this.#_view;
  }
  set view(value: DataView) {
    this.#_view = value;
  }
  constructor(packetBytes: number[]) {
    this.view = new DataView(Uint8Array.from(packetBytes).buffer);
    this.ethernet = new Ethernet(packetBytes);
    this.ip = new IP(packetBytes.slice(Ethernet.size));
    let procSize = 0;
    if (this.ip.Protocol === 6) {
      this.tcp = new TCP(this.ip, packetBytes.slice(Ethernet.size + IP.size));
      procSize = TCP.size;
    } else if (this.ip.Protocol === 17) {
      this.udp = new UDP(this.ip, packetBytes.slice(Ethernet.size + IP.size));
      procSize = UDP.size;
    }
    this.data = new Data(packetBytes.slice(Ethernet.size + IP.size + procSize));
  }
}
const udpData =
  "70 89 cc ee 84 2c 3c 2c 30 a6 a2 d0 08 00 45 80 00 7b c9 5b 00 00 80 11 00 00 c0 a8 01 06 b7 e8 7f f4 0f a5 1f 40 00 67 c7 76 02 39 3d 03 e3 4c 72 61 dc 91 5f 04 00 00 00 01 01 01 00 00 69 a1 00 00 00 00 00 00 00 00 da d2 8d 74 3e 33 16 50 ea 46 c0 cf 22 9c 93 7d 7e b3 91 89 e0 c5 b9 e4 22 b6 e6 e9 78 d8 0b 28 6e 42 6d f1 d8 44 43 b1 7f 1b f0 a5 aa a7 d6 e9 4a 07 49 e8 a0 88 a0 42 15 e2 a9 da 21 ed da af 03";
const tcpData =
  "70 89 cc ee 84 2c 3c 2c 30 a6 a2 d0 08 00 45 00 00 68 9b b7 40 00 80 06 00 00 c0 a8 01 06 31 eb 6b da c8 41 0e 96 48 d2 73 52 24 9a 12 8b 50 18 ff ff 5f ce 00 00 54 4c 42 42 30 31 d5 01 18 00 00 7e 0b 84 80 58 0e 03 00 00 00 61 61 61 00 ff ff ff ff 01 00 00 00 00 00 00 54 4c 42 42 30 31 73 03 10 00 00 7f 00 00 00 00 00 00 00 00 00 00 00 00 1e 03 04 00";
const p = new Packet(
  tcpData
    .trim()
    .split(/\s+/)
    .map((it) => parseInt(it, 16))
);
												
											ip/udp/tcp包 学习的更多相关文章
- 网络传输数据封装详解(IP,UDP,TCP)
		
IP数据包也叫IP报文分组,传输在ISO网络7层结构中的网络层,它由IP报文头和IP报文用户数据组成,IP报文头的长度一般在20到60个字节之间,而一个IP分组的最大长度则不能超过65535个字节. ...
 - 【Windows socket+IP+UDP+TCP】网络基础
		
Windows Socket+网络 Winsock是 Windows下套接字标准. Winsock 编程分为UDP[Windows socket + UDP],TCP[Wi ...
 - 以太网,IP,TCP,UDP数据包分析【转】
		
原文地址:http://www.cnblogs.com/feitian629/archive/2012/11/16/2774065.html 1.ISO开放系统有以下几层: 7 应用层 6 表示层 5 ...
 - 以太网,IP,TCP,UDP数据包分析(此文言简意赅,一遍看不懂的话,耐心的看个10遍就懂了,感谢作者无私奉献)
		
1.ISO开放系统有以下几层: 7 应用层 6 表示层 5 会话层 4 传输层 3 网络层 2 数据链路层 1 物理层 2.TCP/IP 网络协议栈分为应用层(Application).传输层(Tra ...
 - 一些重要的计算机网络协议(IP、TCP、UDP、HTTP)
		
一.计算机网络的发展历程 1.计算机网络发展 与其说计算机改变了世界,倒不如说是计算机网络改变了世界.彼时彼刻,你我都因网络而有了交集,岂非一种缘分? 计算机与网络发展大致经历如下过程:
 - [转]SOCKET通信中TCP、UDP数据包大小的确定
		
TCP.UDP数据包大小的确定 UDP和TCP协议利用端口号实现多项应用同时发送和接收数据.数据通过源端口发送出去,通过目标端口接收.有的网络应用只能使用预留或注册的静态端口:而另外一些网络应用则可以 ...
 - ETHERNET数据包格式( IP & UDP & ICMP & ARP )
		
ETHERNET数据包格式( IP & UDP & ICMP & ARP ) ETHERNET数据包格式 一.ETHERNET 数据包的协议类型 TYPE 的值为 0x0800 ...
 - [转]TCP、UDP数据包大小的确定
		
TCP.UDP数据包大小的确定 http://blog.163.com/jianlizhao%40126/blog/static/1732511632013410101827640/ U ...
 - TCP、UDP数据包大小的限制(UDP数据包一次发送多大为好)——数据帧的物理特性决定的,每层都有一个自己的数据头,层层递减
		
1.概述 首先要看TCP/IP协议,涉及到四层:链路层,网络层,传输层,应用层. 其中以太网(Ethernet)的数据帧在链路层 IP包在网络层 TCP或UDP包在传输层 TCP或UDP中的数据(Da ...
 
随机推荐
- scala/java等其他语言从CSV文件中读取数据,使用逗号','分割可能会出现的问题
			
众所周知,csv文件默认以逗号","分割数据,那么在scala命令行里查询的数据: 可以看见,字段里就包含了逗号",",那接下来切割的时候,这本应该作为一个整体 ...
 - Fody,告别烦人的INotifyPropertyChanged,最简方式实现通知!
			
INotifyPropertyChanged 我不是针对谁,我是说在座的各位 相信所有学wpf的,都写过类似下面的代码: 实现INotifyPropertyChanged public class M ...
 - Result Maps collection already contains value for xxxMapper.BaseResultMap错误解决办法
			
原因分析: 这些代码因为是工具自动生成的,所以也没仔细检查.一个小小的错误,导致的. 解决办法: 1.由于使用ibatis的TempTestTableMapper.xml实现接口TempTestTab ...
 - jQuery基础介绍
			
最近在学习JavaScript,当学习Javascript之后,不得不学习的肯定是jQuery了,所以开始利用网络的便捷浏览各大博客寻找可学习的资源.这篇博客关于jQuery的学习让我有很多收获,也明 ...
 - python----类,面向对象(封装、继承、多态)(属性,方法)
			
什么是对象? 对象是内存中专门用来存储数据的一块区域 对象中可以存放各种数据(数字.代码等) 对象由三部分组成(1,对象标识(id)2,对象类型(type)3,对象的值(value)) 面向对象编程是 ...
 - 虚拟局域网(VLAN)__语音VLAN
			
1.语音VLAN特性使得访问端口能够携带来自IP电话的IP语音流量.当交换机连接到Cisco IP电话时,IP电话就用第3层IP优先级(precedence)和第2层服务级别(class of ser ...
 - 若依管理系统RuoYi-Vue(一):项目启动和菜单创建
			
若依管理系统应该是国内最受欢迎的完全开源的后端管理系统了吧,看看gitee上的star数量,着实惊人.若依系统有很多个版本 版本 gitee地址 说明 前后端不分离版本 https://gitee.c ...
 - 从微信小程序到鸿蒙js开发【04】——list组件
			
目录: 1.可滚动区域 2.list + list-item 3.list + list-item-group + list-item 1.可滚动区域 在许多场景中,页面会有一块区域是可滚动的,比如这 ...
 - Qt项目的发布
			
Qt项目的发布 (1)首先将项目调为发布版 (2)找到缺失的DLL文件 发布好了后,双击生成的exe文件可能会出现如下的问题 像这样的错误警告可能会弹出好几个,对于这种错误有2种解决方案. 第一种:配 ...
 - 使用eclipse写第一个Java_web的hello_world项目
			
1.先创建一个Java_web项目 如果你没有下载过Tomcat服务器,不会配置,建议看一下我得这一篇博客:https://www.cnblogs.com/kongbursi-2292702937/p ...