网络通信:不同主机、进程间通信。
一.基本概念
1.OSI七层模型
国际标准化组织(ISO)提出的网络体系结构模型称为开放系统互连参考模型(OSI/RM),简称OSI参考模型。OSI参考模型有7层,自下而上(第1~7层)依次为物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。记忆口诀:物联网叔会使用。OSI参考模型的层次结构如图1.9所示。

下面详述OSI参考模型各层的功能
1.物理层
物理层的传输单位是比特,功能是在物理介质上为数据端设备透明地传输原始比特流。图1.10表示的是两个通信节点及它们之间的一段通信链路,物理层主要研究以下内容:
1)通信链路与通信节点的连接需要一些电路接口,物理层规定了这些接口的一些参数,如机械形状和尺寸、引脚的数量和排列等,例如笔记本电脑上的网线接口。
2)物理层规定了通信链路上所传输的信号的意义和电气特征。例如,若规定信号X代表数字0,则当节点传输0时就发出信号X,而当节点接收到信号X时就知道收到的是0。注意,传输信息所用的一些物理介质(如双绞线、光缆、无线信道等)并不在物理层协议之内,而在物理层协议下面。因此,有人将物理介质当作第0层。
2.数据链路层
数据链路层的传输单位是帧。两台主机之间的数据传输总是在一段一段的链路上进行的,这就需要使用专门的链路层协议。主要作用是加强物理层传输原始比特流的功能,将物理层提供的可能出错的物理连接改造为逻辑上无差错的数据链路。数据链路层将网络层交来的IP分组封装成帧,并且可靠地传输到相邻节点的网络层,实现节点之间的差错控制和流量控制的功能。
因为外界噪声的干扰,所以原始的物理连接在传输比特流时可能发生错误。如图1.10所示,节点A想向节点B传输数字0,于是发出信号X;但在传输过程中受到干扰,信号X变成了信号Y,而信号Y又刚好代表1,节点B接收到信号Y时,误以为节点A传送了数字1,从而发生差错。差错控制可以检测出这些差错,然后将收到的错误信息丢弃。
如图1.10所示,在两个相邻节点之间传送数据时,节点A的发送速率可能比节点B的接收速率快,若不加以控制,则节点B就会丢弃很多来不及接收的正确数据,造成传输线路效率下降。流量控制可以协调两个节点的速率,使节点A的发送速率刚好是节点B的接收速率。
广播式网络在数据链路层还要处理新的问题,即如何控制对共享信道的访问。
3.网络层
网络层的传输单位是数据报。它关心的是通信子网的运行控制,主要任务是将网络层的协议数据单元(分组)从源主机传输到目的主机,为分组交换网上的不同主机提供通信服务。关键问题是对分组进行路由选择,并实现流量控制、拥塞控制、差错控制和网际互联等功能。网络层既提供有连接可靠的虚电路服务(TCP),又提供无连接不可靠的数据报服务(UDP)。
无论是在哪一层传送的数据单元,都可以笼统地用“分组”来表示。
在如图1.11所示的某网络结构图中,当节点A向节点B传输一个分组时,既可经过边a、c、g,也可经过边b、h,有多条可以选择的路由,而网络层的作用是根据网络的情况,利用相应的路由算法计算出一条合适的路径,使这个分组可以顺利地到达节点B。
流量控制与数据链路层的流量控制的含义一样,都是协调A的发送速率和B的接收速率。若图1.11中的节点都来不及接收分组而丢弃大量分组,导致节点间无法正常通信,则网络处于拥塞状态。网络层要采取措施来缓解这种拥塞,这就是拥塞控制。
差错控制是通信节点之间约定的特定检错规则,接收方根据该规则检查接收到的分组是否出错,若出错,则能纠错就纠错,不能纠错就丢弃,确保向上层提交的数据都是无误的。
4.传输层
传输层也称运输层,负责主机中两个进程之间的通信,提供端到端的流量控制、差错控制、连接建立与释放、可靠传输管理等服务,传输层仅提供有连接可靠的服务。
数据链路层提供的是点到点通信,传输层提供的是端到端通信,两者不同。
通俗地说,点到点可理解为主机和主机之间的通信,一个点是指一个硬件地址或IP地址,网络中参与通信的主机是通过硬件地址或IP地址来标识的;端到端通信是指运行在不同主机内的两个进程之间的通信,一个进程由一个端口来标识,因此称为端到端通信。
通过传输层的屏蔽,高层用户看不到通信子网的交替和变化。因为一台主机可同时运行多个进程,所以传输层具有复用和分用的功能。复用是指多个应用层进程可同时使用下面传输层的服务,分用是指传输层将收到的信息分别交付给上面应用层中相应的进程。
5.会话层
会话层允许不同主机上的各个进程之间进行会话。这种服务主要为表示层实体或用户进程建立连接,并在连接上有序地传输数据,这就是会话,也称建立同步(SYN)。会话层负责管理主机间的会话进程,包括建立、管理和终止进程间的会话。会话层包含一种称为检查点的机制来维持可靠会话,使通信会话在通信失效时从检查点继续恢复通信,即断点下载的原理。
6.表示层
表示层主要处理在不同主机中交换信息的表示方式。不同机器采用的编码和表示方法不同,为了使不同表示方法的数据和信息之间能够互相交换,表示层采用抽象的标准方法定义数据结构,并采用标准的编码形式。此外,数据压缩、加密和解密也是表示层的功能。
7.应用层
应用层是OSI参考模型的最高层,是用户与网络的接口。应用层为特定类型的网络应用提供访问OSI参考模型环境的手段。用户的实际应用多种多样,这就要求应用层采用不同的应用协议来满足不同类型的应用要求,因此应用层是最复杂的一层,使用的协议也最多。
2.TCP/IP五层模型

1)应用层
HTTP:超文本传输协议(超文本:集链接,图像,文字,音视频于一体的文件)应用于浏览器和服务器之间通信。
HTTPS:超文本传输协议(SSL加密)
FTP:文件传输协议(传输层采用TCP)
TFTP:简单文件传输协议(传输层采用UDP)
DNS:域名解析协议(域名转化为IP)
MQTT:消息队列遥测传输协议(物联网协议)
2)传输层
TCP :传输控制协议
UDP:用户数据报协议
3)网络层
IPv4 :IP协议
IPv6 : IP协议DHCP:给主机动态分配IP地址
ICMP协议:让主机和路由器报告差错和异常情况
三种路由协议:
RIP, OSPF, BGP
4)数据链路层
ARP : 地址解析协议 IP--->MAC
RARP:逆地址解析协议 MAC --->IP
5)物理层
3.OSI与TCP/IP
OSI模型与TCP/IP参考模型的层次对应关系如下图所示:

4.网络协议栈
协议数据单元(PDU):对等层之间传送的数据单位。
服务数据单元(SDU):层与层之间交换的数据单位。协议控制信息(PCI):控制协议操作的信息。每层的PDU都有一个通俗的名称,如物理层的PDU称为比特流,数据链路层的PDU称为帧,网络层的PDU称为分组,传输层的PDU称为报文段。
当在各层之间传输数据时,将从第n+1层收到的PDU作为第n层的SDU,加上第n层的PCI,就封装成了第n层的PDU,交给第n-1层后作为SDU发送,接收方接收时做相反的处理,网络各层数据单元的联系如图所示。
简单介绍使用协议栈进行通信的数据传输过程。每个协议栈的顶端都是一个面向用户的接口,下面各层是为通信服务的协议。用户传输的数据通常是用户能够理解的自然语言,通过应用层将自然语言转化为用于通信的通信数据。
通信数据到达传输层,作为传输层的服务数据单元(传输层SDU),加上传输层的协议控制信息(传输层PCI),组成传输层的PDU;下放到网络层后,就成为网络层的SDU,加上网络层的PCI,又组成了网络层的PDU;下放到数据链路层.....就这样层层下放,层层包裹,最后形成的数据包通过通信线路传输,到达接收方节点协议栈,接收方逆向逐层地拆开“包裹”,然后将收到的数据提交给用户,如图所示。
端口号: 16位的数值 0-65535 unsigned short
作用:唯一的标识一个网络进程
每一个应用进程都有一个端口号;
通讯时用来区分数据包属于哪一个进程。
分类:
1)任何TCP/IP实现所提供的服务都用1-1023之间的端口号。
http : 80
FTP: 20/21
TFPT: 69
HTTPS: 443
MQTT协议:1883
2)端口号从1024-49151是被注册的端口号,被IANA指定为特殊服务使用。
3)从49152-65535是动态或私有端口号。
二. 网络配置
桥接模式
1. 虚拟机---》设置---》网络适配器----》桥接模式----》确定
2. 编辑---》虚拟网络编辑器---》更改设置---》Vmnet0---》桥接模式---》桥接到:Windows正在上网的网卡--》应用---》确定
3. 修改网络配置文件
sudo vim /etc/network/interfaces
auto lo
iface lo inet loopback
auto ens33
iface ens33 inet dhcp
4. 重启网络服务
sudo /etc/init.d/networking restart
如果网络重启不行:
系统重启
sudo reboot
5. ifconfig
查看Linux下的网卡信息
ipconfig
查看windows下的网卡信息
6.ping www.baidu.com
检查网络是否为通
三. UDP协议
传输层:
UDP协议:用户数据报协议(User Datagrams Protocal)
UDP特点:
1.无连接
2.面向数据报
3.尽最大努力交付协议,不安全不可靠(丢包,乱序)
4.机制简单,实时性好,效率高
适合直播、游戏画面
1. 网络通信模型
B/S :Browser/Server : 浏览器/服务器
1. 通用客户端(浏览器作为通用客户端)
2. 数据资源基本都保存在服务端
3. 只需要开发服务端
C/S :Client / Server :客户端/服务端
1. 专用客户端
2. 客户端和服务端都可以保存资源
3. 客户端和服务端都需要开发
2. UDP编程
客户端:
服务端:

- socket
int socket(int domain, int type, int protocol);
功能:创建通信的套接字
参数:
domain:使用的协议族
AF_INET : IPv4 (网络层)
AF_INET6 :IPv6
type :传输层的协议类型
SOCK_STREAM : TCP
SOCK_DGRAM : UDP
protocol :0 默认方式
返回值:
成功:文件描述符(套接字)
失败:-1int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket"); return -1; }
套接字:应用层网络通信的端口,文件描述符
- sendto
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
功能:发送udp数据报文
参数:
sockfd:套接字
buf : 要发送的数据首地址
len:发送的数据字节数
flags : 0 按照默认方式发送
dest_addr:服务端的地址信息(IP + PORT)
addrlen :地址信息的长度
返回值:
成功:发送的字节数
失败:-1
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
/* Internet address. */
struct in_addr {
uint32_t s_addr; /* address in network byte order*/
};
struct sockaddr相当于“基类”(通用地址)。它只定义了地址类型,但具体内容是个“黑盒子”。
struct sockaddr_in相当于“派生类”(IPv4 专用地址)。它清楚地划分了端口、IP 地址等具体字段,方便赋值。0x1122
0x2211
网络字节序:大端 (高地址存低字节位,低地址存高字节位)
主机字节序:小端 (高地址存高字节位,低地址存低字节位)ssize_t size = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&server, sizeof(server)); if (size < 0) { perror("sendto error"); exit(1); } printf("send size = %ld\n",size);
host--》net s short l 4字节
- htons :2字节数据,主机字节序转网络字节序
- htonl :4字节数据,主机字节序转网络字节序
- ntohs :2字节数据,网络字节序转主机字节序
- ntohl :4字节数据,网络字节序转主机字节序
- inet_addr
in_addr_t inet_addr(const char *cp);
功能:将点分十进制的字符串IP地址转换成32位的二进制IP地址形式
参数:
cp:字符串IP地址
返回值:
整形ip地址server.sin_addr.s_addr = inet_addr("192.168.85.129");
- bind
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
功能:绑定当前套接字和IP地址及端口号
参数:
sockfd:套接字
addr:要绑定的地址信息指针
addrlen:地址信息的长度
返回值:
成功:0
失败:-1struct sockaddr_in server; server.sin_family = AF_INET; server.sin_port = htons(50000); server.sin_addr.s_addr = inet_addr("192.168.85.129"); int ret = bind(sockfd, (struct sockaddr *)&server, sizeof(server)); if(ret < 0) { perror("bind error"); return -1; }
- recvfrom
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
功能:接收UDP数据报文
参数:
sockfd:套接字
buf:存储网络接收到的数据
len :期望接收到的字节数
flags:0 默认方式接收
src_addr:保存发送发地址信息的指针addrlen:地址长度的指针
返回值:
成功:实际接收到的字节数
失败:-1
0 :当对方发送0字节数据包struct sockaddr_in client; socklen_t len = sizeof(client); ssize_t size = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&client, &len); if(size < 0 ) { perror("recvfrom error"); return -1; }UDP接收端可同时接收多个IP发来的数据,关闭传输时使用recvfrom返回值为0进行终止
char *inet_ntoa(struct in_addr in);
功能:将结构体类型的IP地址转换成字符串的IP地址
3.UDP报文头部
| 源端口号(2字节) | 目的端口号(2字节) |
| 数据包长度(2字节) | 校验和(checksum)(2字节) |
四.网络抓包工具
wireshark:网络抓包工具,可以抓取经过网卡的网络数据,从而分析网络问题和网络数据。
Linux下安装wireshark:
sudo apt-get install wireshark
抓包流程:
1. 启动wireshark : sudo wireshark
2. 选择抓取的网卡:any
3. 选择抓取数据包的过滤条件并触发:udp.port == 50000
4. 进行网络通信
五. TCP协议
传输层
TCP: 传输控制协议(流式套接字)
1. TCP特点
1. 有连接;
2. 面向字节流;(传输中会拆包、装包)
3. 安全可靠的传输协议
三次握手、四次挥手、应答机制、超时重传机制....等
4. 机制复杂,实时性和效率没有UDP高
HTTPS、MQTT、FTP
2. TCP的三次握手和四次挥手机制
三次握手:TCP建立连接时,通过三次握手,来确保通信双方都已经准备就绪。
三次握手由客户端发起。

第一步:客户机首先向服务器发送连接请求报文段。请求报文段的SYN位置1,同时选择一个初始序号seq=x。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但要消耗一个序号。这时,客户机进入SYN-SENT(同步已发送)状态。
第二步:服务器收到连接请求报文段后,如同意建立连接,则向客户机发回确认。确认报文段的SYN位和ACK位都置1,确认号ack=x+1,同时选择一个初始序号seq=y。确认报文段不能携带数据,但也要消耗一个序号。这时,服务器进入SYN-RCVD(同步收到)状态。第三步:客户机收到确认报文段后,还要向服务器给出确认。确认报文段的ACK位置1,确认号ack=y+1,序号seq=x+1。该报文段可以携带数据。若不携带数据,则不消耗序号,下一个数据报文段的序号仍为x+1。这时,客户机进入ESTABLISHED(已建立连接)状态。当服务器收到来自客户机的确认后,也进入ESTABLISHED状态。
成功进行以上三步后,就建立了TCP连接,接下来就可以传送应用层数据。TCP提供的是全双工通信,因此通信双方的应用进程在任何时候都能发送数据。
四次挥手:TCP断开连接时,通过四次挥手,确保通信双发数据都已经收发结束。

第一步:客户机打算关闭连接时,向服务器发送连接释放报文段,并停止发送数据,主动关闭TCP连接,该报文段的FIN位置1,序号seq=u,它等于前面已传送的数据的最后一个字节的序号加1,FIN报文段即使不携带数据,也要消耗一个序号。这时,客户机进入FIN-WAIT-1(终止等待1)状态。TCP是全双工的,即可以想象为一条TCP连接上有两条数据通路,发送FIN的一端不能再发送数据,即关闭了其中一条数据通路,但对方还可以发送数据。
第二步:服务器收到连接释放报文段后即发出确认。该报文段的ACK 位置1,确认号ack=u+1,序号scq=v,等于它前面已传送过的数据的最后一个字节的序号加1。然后服务器进入CLOSE-WAIT(关闭等待)状态。此时,从客户机到服务器这个方向的连接就释放了,但从服务器到客户机这个方向的连接并未关闭,TCP连接处于半关闭状态。客户机收到来自服务器的确认后,进入FIN-WAIT-2(终止等待2)状态,等待服务器发出的连接释放报文段。
第三步:若服务器已经没有要向客户机发送的数据,就向其发送连接释放报文段。该报文段的FIN位和ACK位都置1,序号seq=w(处于半关闭状态的服务器可能又发送了一些数据),还必须重复发送上次已发送的确认号ack=u+1。这时服务器进入LAST-ACK(最后确认)状态。
第四步:客户机收到连接释放报文段后,必须发出确认,之后进入TIME-WAIT(时间等待)状态。该报文段的ACK位置1,确认号ack=w+1,序号seq=u+1。服务器收到该确认报文段后就进入CLOSED(连接关闭)状态。客户机进入TIME-WAIT状态后,还要经过时间等待计时器设置的时间2MSL(Maximum Segment Lifetime,最长报文段寿命)后,才进入CLOSED状态。若服务器收到连接释放请求后不再发送数据,则从客户机发出FIN报文段时刻算起,客户机释放连接的最短时间为1RTT+2MSL,服务器释放连接的最短时间为1.5RTT。除时间等待计时器外,TCP还使用一个保活计时器,以避免客户机突然出现故障,而导致服务器一直无效等待。服务器每收到一次客户的数据,就会重置保活计时器,若计时到期后还没有收到客户的数据,服务器就每隔75秒发送一个探测报文段。若连续发送10个探测报文段后仍未收到客户的响应,则服务器认为客户机出了故障,关闭这个连接。
释放连接时也可能由于被释放端再无数据传输而变为三次挥手
3. TCP编程
客户端:socket()-->connect()-->send()-->recv()-->close()
服务端:socket()-->bind()-->listen()-->accept()-->recv()-->send()-->close()

- connect
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
功能:请求建立连接
参数:
sockfd:套接字
addr :服务端的地址
addrlen:地址长度
返回值:
成功:0
失败:-1struct sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(50000); server_addr.sin_addr.s_addr = inet_addr("192.168.85.129"); if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("connect error"); exit(1); }
- listen
int listen(int sockfd, int backlog);
功能:监听客户端的三次握手
参数:
sockfd:监听套接字
backlog:最多允许监听的客户端的个数
返回值:
成功:0
失败:-1if (listen(sockfd, MAX_CLIENT) < 0) { perror("listen"); return -1; }
- accept
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:接收完成三次握手的客户端,并返回一个通讯套接字
参数:
sockfd:监听套接字
addr:保存接入的客户端的地址信息的指针
addrlen:地址信息长度的指针
返回值:
成功:通讯套接字
失败:-1int connfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len); if(connfd < 0) { perror("accept"); continue; } printf("client ip: %s, port: %d\n", inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
- recv
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:接收网络数据
参数:
sockfd:通讯套接字
buf:存放接收到的数据的空间首地址
len:期待接收到的字节数
flags: 0 默认方式
返回值:
成功:返回实际收到的字节数
失败:-1
0:发送断开连接char buf[1024] = {0}; while(1) { memset(buf, 0, sizeof(buf)); ssize_t size = recv(connfd, buf, sizeof(buf), 0); if(size < 0) { perror("recv"); break; } else if(size == 0) { printf("client close\n"); break; } printf("recv: %s\n", buf); }
4.TCP报文头部

标志位:
TCP报文头部数据位:
SYN:请求建立连接标志位
ACK :效应报文标志位
PSH:携带数据的报文标志位
FIN:请求断开连接标志位
URG:紧急数据标志位
RST:重置标志位
5.TCP机制
三次握手机制:
四次挥手机制:
应答机制:TCP为发送的数据进行编号,发送数据时,报文头部的序列号是这包数据的第一个数据的编号;将来接收方需要给这包数据发送ACK,ACK报文中确认号是收到的最后一个字节编号+1;
超时重传机制:TCP每发送一包数据后都要等待应答,如果超时时间之内没有收到应答,则重新发送这包数据。
其中rwnd表示剩余窗口大小,用来告知对方自己剩余空间大小
滑动窗口机制:缓冲区,保存已发送并收到应答的数据、已发送未收到应答的数据、未发送但在对方处理范围内的数据。
延迟应答机制(即累计确认):TCP可以发送多组数据,发送的同时等待应答。
流量控制机制:TCP会根据发送端的数据处理和接收能力调整自己的发送速率,根据ACK中窗口值的大小进行动态调整流量。
捎带应答机制:ACK可以和应用层发送的数据一起发出,表示对上包数据的响应。
TCP连接总结:
6. TCP粘包
粘包:发送端发送速度太快,接收端处理速度比较慢,导致数据在缓冲区缓存,应用层读出数据
时,多包数据发生了粘连。
如何解决:
1. 收发指定大小数据(收发结构体)
注意:跨平台发送时平台的位数。
struct data
{
xxx;
long num;//注意跨平台,32位和64位平台
};
send(sockfd, &data, sizeof(struct data), 0);
recv(sockfd, &data, sizeof(struct data), 0);
2. 给发送的数据明显的分割符,应用层根据分隔符解析
hello\n
world\n
hello\nworld\n
3. 以自定义方式定义发送的数据帧格式,接收方严格按照协议方式解析
帧头 数据长度 消息类型 校验 帧尾
5A 0101 1010
A5
7E
E7
EB90
消息类型 :区分数据包的数据类型
校验:8位和校验:checksum
16位和校验
CRC校验
AA 0C 01 00 00 00 10 00 00 01 00 00 00 11 00 sum BB
AA 0F 02 00 00 00 01 00 00 00 10 00 00 01 00 00 00 11 00 sum BB
AA 0C 01 00 00 00 10 00 00 01 00 00 BB 11 00 sum BB AA 0F 02 00 00 00 01 00
00 00 10 00 00 01 00 00 00 11 00 BB









48

被折叠的 条评论
为什么被折叠?



