文章目录
- 网络通信
-
- 一、网络通信的基本概念
- 二、OSI七层模型(理论模型)
- 三、TCP/IP模型(生产模型)
-
- [3.1 四层模型:](#3.1 四层模型:)
- [3.2 五层模型:](#3.2 五层模型:)
- [3.3 各层常用的一些协议](#3.3 各层常用的一些协议)
- [3.4 IP协议:](#3.4 IP协议:)
- [3.5 IP地址的划分:](#3.5 IP地址的划分:)
- 四、网络协议栈
- 五、数据包的封装和解封过程
- 六、网络配置
- 七、UDP协议
-
- [7.1 UDP通信](#7.1 UDP通信)
- [7.2 UDP通信相关函数接口](#7.2 UDP通信相关函数接口)
-
- [7.2.1 socket()](#7.2.1 socket())
- [7.2.2 sendto()](#7.2.2 sendto())
- [7.2.3 bind()](#7.2.3 bind())
- [7.2.4 recvfrom()](#7.2.4 recvfrom())
- [7.2.5 辅助函数](#7.2.5 辅助函数)
- [7.3 UDP使用示例](#7.3 UDP使用示例)

网络通信
一、网络通信的基本概念
网络通信:不同主机间的进程间通信。
- 主机1和主机2在物理层面互联互通;
- 主机1和主机2在软件层面互联互通。

传输一个数据一般会包括下面几个信息:
IP地址:计算机的软件地址,标记主机
MAC地址:计算机的硬件地址,局域网内通信
端口号:识别同一主机上的不同网络进程
二、OSI七层模型(理论模型)
OSI:开放系统互联模型
- 应用层;要传输的数据信息,如文件传输,电子邮件等。
- 表示层;数据加密,解密操作,压缩,解压缩。
- 会话层;建立数据传输通道。
- 传输层;传输的方式 UDP TCP 端口号。
- 网络层;实现数据路由 路径规划 路由器 ip。
- 数据链路层;封装成帧,点对点通信(局域网内通信) 差错检测 交换机 ARP
- 物理层;定义物理设备标准,比如网线、光纤等传输介质 传输比特流 bit 0 1
三、TCP/IP模型(生产模型)
3.1 四层模型:
应用层:应用层、表示层、会话层
传输层:传输层
网络层:网络层
网络接口层:数据链路层、物理层
3.2 五层模型:
应用层:应用层、表示层、会话层
传输层:传输层
网络层:网络层
数据链路层:数据链路层
物理层:物理层
3.3 各层常用的一些协议
-
应用层 :
HTTP协议:超文本传输协议(超文本:集链接、图片、文字音视频等一体的文件。)
HTTPS协议:超文本传输协议(SSL加密)
FTP:文件传输协议(TCP)
TFTP:简单传输协议(UDP)
DNS服务:域名解析服务:把域名转化成IP地址
MQTT协议:消息队列遥测传输协议(物联网协议)
-
传输层 :
TCP协议:传输控制协议(流式套接字)
UDP协议:用户数据报协议
-
网络层 :
IPv4:IP协议
IPv6:IP协议
-
数据链路层 :
MAC<------>IP
ARP协议:地址解析协议
RARP:逆地址解析协议
-
物理层:
3.4 IP协议:
IPv4 :32位
IPv6:128位 (主要解决IPv4地址不够用而产生的)
例如 :
192.168.1.3 (用户表示形式) 点分十进制
1100 0000 1010 1000 0000 0001 0000 0011 (计算机存储形式) 32bit
IP地址 = 网络位 + 主机位
网络位 :该IP地址位于哪个网段(局域网)内
主机位:这个网段的位数
tips:linux查看ip地址终端指令: ifconfig

ens33 :实际进行数据发送的网卡;
lo:本地回环网卡(自己发数据自己收)
当前主机IP地址:inet 192.168.87.128
子网掩码 :netmask 255.255.255.0
1111 1111.1111 1111.1111 1111.0000 0000
用来区分IP地址的网络位和主机位,搭配IP地址使用。
子网掩码是1的部分对应IP地址的网络位
子网掩码是0的部分对应IP地址的主机位
有的也这样表示:
192.168.0.121/24
24:网络位的位数
这样就不用子网掩码也能区分网络位和主机位。
网段号 :
IP地址网络位不变,主机位全为0,则为该IP地址的网段号
192.168.1.3
255.255.0.0
192.168.0.0(网段号)
广播号 :
192.168.1.255
IP地址网络位不变,主机位全为1,则为该IP地址的广播号
192.168.1.3
255.255.255.0广播号:
192.168.1.255(向广播号发送信息,所有局域网内IP都能收到此信息)
网关地址:192.168.1.1
3.5 IP地址的划分:
(1)A类地址:
范围:1.0.0.0 - 126.255.255.255
子网掩码:255.0.0.0 126*2^24
用于管理大规模网络
私有IP地址:10.0.0.0 - 10.255.255.255
127.0.0.0 回环地址
(2)B类地址:
范围:128.0.0.0 - 191.255.255.255
子网掩码:255.255.0.0 2^16
管理大中规模网络
私有IP地址:172.16.0.0 - 172.31.255.255
(3)C类地址:
范围:192.0.0.0 - 223.255.255.255
子网掩码:255.255.255.0 2^8
管理中小规模网络
私有IP地址:192.168.0.0 - 192.168.255.255
(4)D类地址:
224.0.0.0 - 239.255.255.255
组播和广播使用
(5)E类地址:
240.0.0.0 - 255.255.255.254
组播和广播使用
公有IP :电信公司直接分配,并需要付费的IP地址,可以直接访问internet
私有IP:不能直接访问internet的ip地址
四、网络协议栈
IP+PORT:可以找到目标主机上的目标进程
端口号 :16位的数值 0-65535 unsigned short
作用 :唯一的标识一个网络进程
每一个应用进程都有一个端口号;
通讯时用来区分数据包属于哪一个进程。
分类:
-
任何TCP/IP实现所提供的服务都用1-1023间的端口号。
http: 80
FTP:20/21
TFPT: 69
HTTPS: 443
MQTT:1883
-
端口号从1024-49151是被注册的端口号,被IANA指定为特殊服务使用。
-
从49152-65535是动态或私有端口号。
五、数据包的封装和解封过程

六、网络配置
桥接模式
-
点击右上角虚拟机------>点击设置------>点击网络适配器------>桥接模式------>已连接和启动时连接也勾选上
-
编辑------>虚拟网络编辑器------>更改设置------>Vmnet0------>桥接模式------>桥接到windows正在上网的网卡------>应用------>确定
-
修改网络配置文件:
sudo vim /etc/network/interfaces
dhcp:动态IP分配
-
重启网络服务
sudo /etc/init.d/networking restart如果网络重启不行,就重启系统
sudo reboot -
ifconfig
查看linux系统下的网卡信息

-
ping www.baidu.con
检查网络是否为通。


-
ipconfig
windows系统下查看IP地址。

七、UDP协议
传输层 :
UDP协议:User DataGrames Protocol 用户数据报协议
UDP特点 :
-
无连接;
-
面向数据报;
-
尽最大努力交付协议,不安全不可靠(丢包、乱序);
-
机制简单,实时性效率高。
使用场景:直播、游戏画面
网络通信模型:
-
B/S:Browser/Server:浏览器/服务器
- 通用客户端;
- 数据资源基本都保存在服务端;
- 只需要开发服务端。
-
C/S:Client/Server:客户端/服务端
- 专用客户端;
- 客户端和服务端共同保存数据资源;
- 客户端和服务端都需要开发。
-
P2P
7.1 UDP通信
客户端:
- 创建socket套接字 socket()
- 发送UDP报文 sendto()
- 接受UDP报文 recvfrom()
- 关闭套接字 close()
套接字:应用层网络通信的端口,可以理解为一个文件描述符。
服务端:
- 创建socket套接字 socket()
- 绑定服务端的IP和端口号 bind()
- 接受UDP报文 recvfrom()
- 发送UDP报文 sendto()
- 关闭套接字 close()

7.2 UDP通信相关函数接口
7.2.1 socket()
-
函数原型:
c#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int socket(int domain, int type, int protocol); -
功能: 创建通信的套接字。
-
参数:
domain:使用的协议族;- AF_INET:IPv4;
- AF_INET6:IPv6;
type:传输层的协议类型。- SOCK_STREAM:TCP
- SOCK_DGRAM:UDP
protocol:0默认方式 -
返回值: 成功:文件描述符(套接字);
失败:-1;
7.2.2 sendto()
-
函数原型:
c#include <sys/types.h> #include <sys/socket.h> ssize_t send(int sockfd, const void *buf, size_t len, int flags); 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:结构体的大小(地址的长度)。cstruct 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 */ };c/* Internet address. */ struct in_addr { uint32_t s_addr; /* address in network byte order */ };网络字节序:大端(高地址存低字节位,低地址存高字节位);
主机字节序:小端(高地址存高字节位,低地址存低字节位)。
s_addr需要的是网络地址,因此需要借助后面的辅助函数转化地址信息形式。 -
返回值: 成功:ssize_t 类型发送的字节数;
失败:-1;
7.2.3 bind()
-
函数原型:
c#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen); -
功能: 绑定当前的套接字和IP地址及端口号。
-
参数:
sockfd:套接字;addr:要绑定的地址信息的指针;addrlen:地址信息的长度 -
返回值: 成功:返回0;
失败:返回-1.
7.2.4 recvfrom()
-
函数原型:
c#include <sys/types.h> #include <sys/socket.h> ssize_t recv(int sockfd, void *buf, size_t len, int flags); 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.
7.2.5 辅助函数
inet_addr():将点分十进制的字符串ip地址转换成32位的二进制IP地址形式;
inet_ntoa():将结构体的ip地址转换成点分十进制的字符串ip地址;
htons():2字节数据,主机字节序转网络字节序;
htonl():4字节数据,主机字节序转网络字节序;
ntohs():2字节数据,网络字节序转主机字节序;
ntohl():4字节数据,网络字节序转主机字节序;host------>net,s------>short,l------>long
7.3 UDP使用示例
客户端 :
首先调用socket()创建一个 UDP 套接字,填充服务端的struct sockaddr_in地址结构体,指定服务端 IP 地址与端口号;程序进入循环,通过fgets()读取控制台输入的字符串,使用sendto()将读取到的数据以 UDP 报文的形式发送给指定服务端,打印发送返回值,循环持续接收用户输入并发送数据,最后关闭套接字,实现 UDP 下向服务端持续发送数据的功能。
c
int main()
{
//socket()
//sendto()
//recvfrom()
//close
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(-1 == sockfd)
{
perror("socket error");
return -1;
}
struct sockaddr_in seraddr;
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(50000);
seraddr.sin_addr.s_addr = inet_addr("10.251.215.158");
char buff[1024] = {0};
while (1)
{
fgets(buff, sizeof(buff), stdin);
ssize_t size = sendto(sockfd, buff, strlen(buff), 0, (struct sockaddr *)&seraddr, sizeof(seraddr));
if (-1 == size)
{
perror("sendto error");
return -1;
}
printf("size = %ld\n", size);
}
close(sockfd);
return 0;
}
服务端 :
首先调用socket()创建 UDP 套接字,初始化本机地址信息,通过bind()将套接字绑定到指定 IP 和 50000 端口;随后进入循环,每次先清空接收缓冲区,调用recvfrom()阻塞等待接收 UDP 数据包(不保存对端地址信息),接收成功后打印接收字节数和收到的字符串内容,循环持续等待客户端报文,最终关闭套接字,完成 UDP 服务端接收客户端数据的逻辑。
c
int main(void)
{
//socket()
//bind()
//recvfrom()
//close()
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
perror("socket error");
return -1;
}
struct sockaddr_in seraddr;
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(50000);
seraddr.sin_addr.s_addr = inet_addr("10.251.215.158");
int ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));
if (ret < 0)
{
perror("bind error");
return -1;
}
char buff[1024] = {0};
while (1)
{
memset(buff, 0, sizeof(buff));
ssize_t size = recvfrom(sockfd, buff, sizeof(buff), 0, NULL, NULL);
if (size < 0)
{
perror("recvfrom error");
return -1;
}
printf("size = %ld, buff : %s\n", size, buff);
}
close(sockfd);
return 0;
}