一、字节顺序与大小端序
1.大小端原理
网络通信将数据从一个主机传递到另一个主机。不同的处理器在管理内存单元数据时,对某一个数据需要存放在多个内存单元的处理方式不尽相同。所以,对存储的数据处理结果也不同,目前CPU数据处理类型有大端序和小端序两种方式。
小端序:内存单元的高地址存放数据的高字节位,低地址存放数据的低字节位。
例如:一个无符号数0x12345678存放在0x4000~0x4003地址中;则高字节12存入高地址0x4003中。剩余数据以此类推存放。
大端序与小端序相反。
目前,X86平台采用小端模式(小端序)。而网络字节顺序采用大端序。
2. 检测系统大小端序
一般可以使用共用体检测系统大小端序。详细方法可以查阅资料。因篇幅问题,故不在此赘述。
3.字节顺序转换函数
因为在网络上传输的数据以及不同的主机的字节顺序有差异。因此,在X86平台下编写网络程序时需要注意大小端转换。
但对于单字节数据而言,因为内存最小单元位1字节(8位),所以单字节数据不存在字节顺序问题。字符串是单字节字符组成的集合(字符数组),所以字符串不受影响。非单字节的数据,例如:short,int,float等必须转换字节顺序。
3.1 htons(要转换的数据)
功能:将一个无符号短整型数(16位数)从主机字节顺序转换为网络字节顺序。
参数:一个以主机字节顺序表达的16位数
返回值:返回一个以网络字节顺序表达的16位数。
3.2 htonl(要转换的数据)
功能:将一个无符号长整型数(32位数)从主机字节顺序转换为网络字节顺序。
参数:一个以主机字节顺序表达的32位数
返回值:返回一个以网络字节顺序表达的32位数。
3.3 ntohl(要转换的数据)
功能:将一个无符号长整型数(32位数)从网络字节顺序转换为主机字节顺序。
参数:一个以网络字节顺序表达的32位数
返回值:返回一个以主机字节顺序表达的32位数
3.4 ntohs(要转换的数据)
功能:将一个无符号短整型数(16位数)从网络字节顺序转换为主机字节顺序。
参数:一个以网络字节顺序表达的16位数
返回值:返回一个以主机字节顺序表达的16位数
3.5 结构体的传送
对于结构体的传送,发送方和接收方都必须知道发送的结构体的定义。
二、IP地址
1. 概念
在TCP/IP中,IP地址在逻辑上唯一标识了一台主机,连接到公网的主机地址是唯一的,一个IP对应一台主机(除私有IP地址和经过映像处理的IP地址)。
2. IP地址表示形式和分类
IP地址有二进制表示法和点分十进制表示法。IP地址是以32位(4字节)二进制形式存储在计算机中的,但为了便于记忆,我们日常使用的是点分十进制形式的IP地址。每个IP地址由网络号和主机号组成。
2.1 点分十分进制IP地址
图 1:IP地址分类
网络ID:标识一个物理的网络,用以网络中的所有主机使用同一个网络号,拥有相同网络号且在物理上连接的(即联网)主机之间通信不需要路由设备。即它们在一个局域网内。
主机ID:确认网络中的一个工作端,服务器、路由器或者其他TCP/IP主机。对于同一个网络号来说,主机号是唯一的。
2.2 IP地址分类:
A类地址:1.0.0.0~127.255.255.255,大型网络
B类地址:128.0.0.0~191.255.255.255,中型网络
C类地址:192.0.0.0~223.255.255.255,小型网络
D类地址:224.0.0.0~239.255.255.255 组播地址
E类地址:240.0.0.0~255.255.255.255 科研地址
其中127.0.0.1 为回环地址,代表自己
255.255.255.255为全局广播地址
主机号为0的地址为该网段地址
2.3 子网掩码
TCP/IP上的每台主机都需要用一个子网屏蔽号。它是一个4字节的地址,用来封装或屏蔽IP的一部分,以区别网络号和主机号。
子网掩码中,对应的IP网络号都被置为1;所有主机号都置为0。
网络地址可由IP地址和子网掩码作与运算(AND)得出。
作用:判别主机发送的数据是向外网发送还是向内网发送
2.4 IPv4地址转换
2.4.1 inet_addr(要转换的点分十进制的IP地址)
功能 :将点分十进制的字符串转换成32位的网络字节顺序的IP信息
参数:点分十进制的IP信息
返回值:返回网络字节顺序的32位IP地址。
2.4.2 inet _network(要转换的点分十进制的IP地址)
功能 :将点分十进制的字符串转换成32位的主机字节顺序的IP信息
参数:点分十进制的IP信息
返回值:返回主机字节顺序的32位IP地址。
2.4.3 inet_ntoa(要转换的网络字节顺序的IP信息)
功能:将32位的网络字节顺序的IP信息转换成点分十进制的字符串形式
参数:网络存储顺序的IP地址
返回值:返回点分十进制的字符串IP地址
2.4.4 inet_aton(参数1,参数2)
功能:将点分十进制的字符串形式转换成32位的网络信息字节顺序;
参数1:要转换的点分十进制的字符串方式IP信息转换成32位的网络字节顺序;
参数2:转换结果的地址空间的首地址(出参);
返回值:成功返回0,失败返回非零。
2.5.基于地址类型转换
目前网络已经从IPv4向IPv6发展,因此需使用以下的函数实现地址类型转换
2.5.1 inet_pton(参数1,参数2,参数3)
功能:将点分十进制的字符串形式转换成32位的网络信息字节顺序
参数1:int af:地址簇(IP协议的类型):IPv4为AF_INET,IPv6为AF_INET6;
参数2:const char *cp:存储要转换的IP地址的存储空间的地址;
参数3:void *buf(结构体):存放转换后的网络信息的地址(出参)IPv4为 struct sockaddr_in,IPv6为struct sockaddr_in6;
返回值:成功返回0,失败返回非零。
2.5.1 inet_ntop(参数1,参数2,参数3)
功能:将32位的网络信息字节顺序转换成点分十进制的形式
参数1:int af:地址簇(IP协议的类型):IPv4为AF_INET,IPv6为AF_INET6;
参数2:const char *cp:存储要转换的IP地址的空间的地址;
参数3:void *buf(结构体):存放转换后的网络信息的地址(出参);IPv4为 struct sockaddr_in,IPv6为struct sockaddr_in6;
参数4:socklen_t len:buf的长度
返回值:成功返回0,失败返回非零。
三、Linux Socket网络编程基础
1.网络通信基础
1.1 TCP/IP协议簇基础
概念:TCP/IP是用于计算机通信的一组协议,因为它包括TCP,IP,UDP,ICMP等多种协议。所以通常称之为 TCP/IP协议簇。
图2:TCP/IP协议簇常用协议
1.2 OSI模型和TCP/IP模型
1.2.1 OSI模型
OSI(open system interconnect):即开放式系统互联。是ISO组织在1985年研究的网络互联模型。OSI将网络划分为7层,即物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
图 3:OSI模型分层结构
1.2.2 TCP/IP模型
TCP/IP将网络划分为4层:应用层,传输层,网络层和网络接口层。
图4:TCP/IP协议分层
(1)网络接口层:模型的基层,负责数据帧的发送和接收(帧是独立的网络信息传输单元)。网络接口层将帧格式的数据放到网络上,或从网络上把帧取下来。
(2)网络层(互连层):互联协议将数据包封装成IP数据包,并运行必要的路由算法,有效的找到到达目的主机最优的路径树。
a. 网络协议IP:负责在主机和网络之间路径寻址和路由数据包。目前主要为IPv4地址,IPv6地址已经在教育网中广泛使用。
b. 地址解析协议ARP:获得同一物理网络中的主机硬件地址。
c. 网际控制消息协议ICMP:发送消息,并报告有关数据包的传送错误。
d. 互联组管理协议:用来实现本地多路组播路由器报告。
(3)传输层:传输协议在主机之间提供通信会话。传输协议的选择根据数据传输方式而定。主要有以下两个传输协议:
a. 传输控制协议TCP: 为应用程序提供可靠的通信连接。适合一次传输大量数据的情况,并适用于要求得到响应的应用程序。
b. 用户数据包协议UDP:提供了无连接通信,且不对传送包进行可靠性确认。适合一次传输小量数据(一般小于520字节)。
(4)应用层:应用程序通过这一层访问网络,主要包括常见的FTP,HTTP,DNS和TELNET协议
a. TELNET:提供远程登录服务。
b. FTP:提供应用级的文件传输服务。
c. SMTP:电子邮件协议。
d. SNMP:简单网络管理协议。
e. DNS:域名解析服务,将域名映像成IP地址的协议。
f. HTTP:超文本传输协议,Web服务器所采用的协议。
1.3 网络数据包封包与拆包过程
图5:数据包的封包与拆包流程图
1. 以太网链路层数据帧(以太网头)格式
图6: 以太网链路层数据帧格式图
2. IP数据包头
图7:IP数据包头图
3. TCP数据包头
图8:TCP数据包头图
4. UDP数据包头
图9:UDP数据包头图
四、TCP协议网络编程
1.三次握手四次挥手
1.1 三次握手发生在请求连接时
图10:三次握手流程图
1.2 四次挥手发生在请求断开时
图11:四次挥手流程图
2.TCP网络编程步骤
2.1 服务器步骤
图12:TCP服务器端流程图
2.2 客户端步骤
图13:TCP客户端流程图
3. I/O多路复用
3.1 多用于TCP协议
int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);
函数功能:系统调用select()提供轮循等待的方式从多个文件描述符中获取状态变化后的情况。
参数1:文件描述符集合的大小,这个参数值为最大文件描述符的值+1。
参数2:包含所有因状态变成可读而触发的select()函数返回的文件描述符
参数3:包含所有因状态变成可写而触发的select()函数返回的文件描述符
参数4:包含所有因状态变发生特殊异常(如带外数据到来)而触发的select()函数返回的文件描述符
返回值:如果函数执行错误,返回-1;
如果因超时而返回,即在timeout所描述的时间范围内没有任何文件描述符有需要的操作,则返回0;并且将该事件结构体清零;
如果因一个或多个文件描述符需要处理而返回,其返回值为产生异常的文件描述符的个数,并在相应的文件描述符集合中清除不需要处理的文件描述符。
3.2 对文件描述符集合的操作函数:
FD_ZERO(fdsetp):初始化fdsetp为空
FD_SET(fd,fdsetp):将fd加入到fdsetp中
FD_ISSET(fd,fdsetp):检测fdsetp中的fd是否发生异常。
FD_CLR(fd,fdsetp):从fdsetp中删除fd。
五、UDP协议网络编程
1.UDP网络编程步骤
1.1 服务器步骤
图14:UDP服务器端流程图
1.2 客户端步骤
图15:UDP客户端流程图