网络基础知识

网络分层

  • 每一层实现不同的功能,对上层的数据做透明传输
  • 每一层向上层提供服务,同时使用下层提供的服务

TCP编程 - 图1

各层典型的协议:

  1. 网络接口与物理层:
    • MAC地址: 48位全球唯一,网络设备的身份标识
    • ARP/RARP:
      • ARP: IP地址——->MAC地址
      • RARP: MAC地址—->IP地址
    • PPP协议: 拨号协议(GPRS/3G/4G)
  2. 网络层:
    • IP: Internet protocol(分为IPV4和IPV6)
    • ICMP: Internet控制管理协议,ping命令属于ICMP
    • IGMP: Internet分组管理协议,广播、组播
  3. 传输层:
    • TCP: (Transfer Control protocol,传输控制协议) 提供面向连接的,一对一的可靠数据传输的协议
      即数据无误、数据无丢失、数据无失序、数据无重复到达的通信
    • UDP: (user Datagram Protocol, 用户数据报协议): 提供不可靠,无连接的尽力传输协议
      是不可靠的无连接的协议。在数据发送前,因为不需要进行连接,所以可以进行高效率的数据传输
    • SCTP: 是可靠传输,是TCP的增强版,它能实现多主机、多链路的通信
  4. 应用层:
    • 网页访问协议:HTTP/HTTPS
    • 邮件发送接收协议: POP3(收)/SMTP(发) 、IMAP(可接收邮件的一部分)
    • FTP
    • Telnet/SSH: 远程登录
    • NTP: 网络时钟协议
    • SNMP: 简单网络管理协议(实现对网络设备集中式管理)
    • RTP/RTSP:用传输音视频的协议(安防监控)

下图为TCP/IP协议通信模型

TCP编程 - 图2

网络的封包和拆包

TCP编程 - 图3

网络编程基础知识

SOCKET

  1. socket是一个应用编程的接口,它是一种特殊的文件描述符(对它执行IO的操作函数,比如,read(),write(),close()等操作函数){% p red::注意没有open函数%}
  2. socket代表着网络编程的一种资源
  3. socket的类型:

TCP编程 - 图4

IP

  1. IP地址分为IPV4和IPV6
    • IPV4:采用32位的整数来表示
    • IPV6:采用了128位整数来表示
  2. IPV4地址:
    • 点分形式: 192.168.7.246
    • 32位整数(4字节)
  3. 特殊IP地址:
    • 局域网IP: 192.XXX.XXX.XXX 10.XXX.XXX.XXX
    • 广播IP: xxx.xxx.xxx.255, 255.255.255.255(全网广播)
    • 组播IP: 224.XXX.XXX.XXX~239.xxx.xxx.xxx

端口

端口号一般由IANA (Internet Assigned Numbers Authority) 管理

端口号是一个16位的数字(1-65535)

  • 众所周知端口: 1~1023(FTP: 21,SSH: 22, HTTP:80, HTTPS:469)
  • 保留端口: 1024-5000(不建议使用)
  • 可以使用的:5000~65535

TCP端口和UDP端口是相互独立的,网络里面的通信是由 IP地址+端口号 来决定

字节序

字节序是指不同的CPU访问内存中的多字节数据时候,存在大小端问题。

大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;

小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。

TCP编程 - 图5

一般来说:

  • X86/ARM: 小端
  • powerpc/mips, ARM作为路由器时,大端模式
  • 网络传输的时候采用大端模式

主机字节序与网络字节序转化:

TCP编程 - 图6

ip地址转化

  1. in_addr_t inet_addr(const char *cp);

特点:

  1. 仅适应于IPV4
  2. 此函数不能用于255.255.255.255的转换

参数:

  1. cp: 点分形式的IP地址,结果是32位整数(内部包含了字节序的转换,默认是网络字节序的模式)

返回值:

  1. 成功:返回转化后的IP地址
  2. 失败:返回-1
inet_pton()
inet_ntop()

特点:

  1. 适应于IPV4和IPV6
  2. 能正确的处理255.255.255.255的转换问题

参数:

  1. af: 地址协议族(AF_INET或AF_INET6)
  2. src:是一个指针(填写点分形式的IP地址[主要指IPV4])
  3. dst: 转换的结果给到dst

返回值:

  1. 成功:返回1
  2. 失败:如果src的格式错误,则返回0
  3. 失败:如果af格式错误,则返回-1

TCP编程API

socket()函数

TCP编程 - 图7

参数:

  1. domain:
    • AF_INET IPv4 Internet protocols
    • AF_INET6 IPv6 Internet protocols
    • AF_UNIX, AF_LOCAL Local communication
    • AF_NETLINK Kernel user interface device
    • AF_PACKET Low level packet interface
  2. type
    • SOCK_STREAM 流式套接字 唯一对应于TCP
    • SOCK_DGRAM 数据报套接字,唯一对应着UDP
    • SOCK_RAW 原始套接字
  3. protocol: 一般填0,原始套接字编程时需填充

返回值:

TCP编程 - 图8

成功时返回文件描述符,出错时返回为-1

bind()函数

TCP编程 - 图9

参数:

  1. sockfd: 通过socket()函数拿到的fd
  2. addr: struct sockaddr的结构体变量的地址
  3. addrlen: 地址长度

通用地址结构体:

struct sockaddr
{    
    u_short  sa_family;    // 地址族, AF_xxx
    char  sa_data[14];     // 14字节协议地址
};

Internet协议地址结构:

struct sockaddr_in
{           
    u_short sin_family;          // 地址族, AF_INET,2 bytes
    u_short sin_port;              // 端口,2 bytes
    struct in_addr sin_addr;      // IPV4地址,4 bytes     
    char sin_zero[8];            // 8 bytes unused,作为填充
};

IPv4地址结构:

struct in_addr
{
    in_addr_t  s_addr;            // u32 network address 
};

实际开发的时候,通过把sockaddr_in结构体强制转化成sockaddr结构体后,作为参数传入bind()函数。

实例:

TCP编程 - 图10

如果是IPV6的编程,要使用struct sockddr_in6结构体(详细情况请参考man 7 ipv6),通常更通用的方法可以通过struct sockaddr_storage来编程。

listen()

把主动套接字变成被动套接字。

TCP编程 - 图11

参数:

  1. sockfd: 通过socket()函数拿到的fd
  2. backlog: 同时允许几路客户端和服务器进行正在连接的过程(正在三次握手)
    一般填5, 测试得知,ARM最大为8

TCP编程 - 图12

比如:listen(fd, 5) 表示系统允许11(=2*5+1)个客户端同时进行三次握手

返回值:

  1. 成功:返回0
  2. 失败:返回-1

accept()

阻塞等待客户端连接请求 。

TCP编程 - 图13

参数:

  1. sockfd: 经过前面socket()创建并通过bind(),listen()设置过的fd
  2. addraddrlen: 获取连接过来的客户的信息

返回值:

  1. 成功:返回已经建立好连接的新的newfd
  2. 失败:返回-1

connect()

客户端的连接函数。

TCP编程 - 图14

connect()函数和服务器的bind()函数写法类似:

参数:

  1. sockfd: 通过socket()函数拿到的fd
  2. addr: struct sockaddr的结构体变量的地址
  3. addrlen: 地址长度

返回值:

  1. 成功:返回0
  2. 失败:返回-1