一、网络协议基础
1. 协议的概念
协议是通信双方约定的一套标准,就像两个人交流要用同一种语言。在网络中,协议规定了数据的格式、传输顺序、差错处理等。
2. OSI七层模型与TCP/IP四层模型
OSI是理想模型,实际应用中是TCP/IP模型:
| 应用层 | 应用层 | 处理应用程序数据 | HTTP、DNS、SMTP |
| 表示层 | (合并) | 数据加密、格式转换 | – |
| 会话层 | (合并) | 建立会话连接 | – |
| 传输层 | 传输层 | 端到端的数据传输 | TCP、UDP |
| 网络层 | 网络层 | 路由选择、跨局域网通信 | IP、ICMP、ARP |
| 数据链路层 | 网络接口层 | 局域网内通信 | Ethernet、PPP |
| 物理层 | (合并) | 物理介质传输 | – |
个人理解:OSI把功能分得很细,但实际TCP/IP将上面三层合并,下面两层合并,更简洁实用。
3. 关键协议简介
-
TCP:传输控制协议,面向连接、可靠、基于字节流。三次握手建立连接,四次挥手断开,还有确认机制、流量控制、拥塞控制,开销大但安全。
-
UDP:用户数据报协议,无连接、不可靠、基于报文。资源开销小,传输速度快,适合实时性要求高的场景(如视频通话、DNS查询)。
-
IP:网际协议,提供跨局域网的路由功能。IPv4地址32位,IPv6地址128位解决地址耗尽问题。
二、IP地址详解
1. IP地址结构
IP地址 = 网络位 + 主机位。网络位决定网段,主机位标识该网段内的设备。
-
子网掩码:用连续的1标识网络位,0标识主机位。例如255.255.255.0表示前24位是网络位。
-
同一网段:网络位相同,可以直接通信。
2. IP地址分类
-
A类:1.0.0.0 ~ 126.255.255.255,掩码255.0.0.0,大型网络。
-
B类:128.0.0.0 ~ 191.255.255.255,掩码255.255.0.0,中型网络。
-
C类:192.0.0.0 ~ 223.255.255.251,掩码255.255.255.0,小型网络。
-
D类:组播地址。
-
E类:实验保留。
3. 公有地址与私有地址
私有地址不能直接上互联网,需通过NAT转换:
-
A类私有:10.0.0.0 ~ 10.255.255.255
-
B类私有:172.16.0.0 ~ 172.31.255.255
-
C类私有:192.168.0.0 ~ 192.168.255.255
三、Linux网络配置与常用命令
1. 虚拟机网络模式
-
桥接模式:Ubuntu与宿主机在网络中地位平等,独立获取IP,可作为服务器。
-
NAT模式:Ubuntu通过宿主机共享上网,IP是虚拟的,不能作为服务器,适合客户端。
2. 常用命令
# 查看网卡信息
ifconfig
# 临时设置IP
sudo ifconfig ens33 192.168.0.108/24 up
# 测试连通性
ping www.baidu.com
# 查看路由
route -n
3. 永久网络配置(以Ubuntu为例)
编辑/etc/network/interfaces:
auto lo
iface lo inet loopback
auto ens33
iface ens33 inet dhcp # 动态获取
# 或者静态配置:
# iface ens33 inet static
# address 192.168.1.100
# netmask 255.255.255.0
# gateway 192.168.1.1
保存后重启网络或重启系统。
四、UDP通信编程
UDP编程相对简单,因为不需要建立连接。主要用到以下几个函数:
1. socket() —— 创建套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
-
AF_INET:IPv4协议族
-
SOCK_DGRAM:数据报套接字(UDP)
-
返回文件描述符,后续读写用此fd。
2. sendto() —— 发送数据
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
-
dest_addr:目标地址结构体,包含IP和端口。
-
addrlen:地址结构体大小。
3. recvfrom() —— 接收数据
类似sendto,不过参数中的sockaddr用于存储发送方地址。
4. 地址结构体与字节序转换
struct sockaddr_in {
sa_family_t sin_family; // AF_INET
in_port_t sin_port; // 端口号(网络字节序)
struct in_addr sin_addr; // IP地址
};
// 主机字节序转网络字节序
uint16_t htons(uint16_t hostshort); // 端口用
uint32_t htonl(uint32_t hostlong); // IP用
// 字符串IP转二进制
in_addr_t inet_addr(const char *cp);
5. 简单UDP通信流程
发送端:
创建socket
设置目标地址(IP+端口)
sendto发送数据
关闭socket
接收端:
创建socket
绑定本地地址(端口)
recvfrom接收数据
处理数据
关闭socket
#include "head.h"
int main()
{
int sockfd = 0;
char tmpbuff[4096]={0};
struct sockaddr_in recvaddr;
ssize_t nert = 0;
sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(-1 == sockfd)
{
perror("fail to socket");
return -1;
}
recvaddr.sin_family = AF_INET;
recvaddr.sin_port = htons(50000);
recvaddr.sin_addr.s_addr = inet_addr("192.168.0.146");
while(1)
{
gets(tmpbuff);
nert = sendto(sockfd,tmpbuff,strlen(tmpbuff),0,(struct sockaddr *)&recvaddr,sizeof(recvaddr));
if(-1 == nert)
{
perror("fail to sendto\\n");
return -1;
}
if(0 == strcmp(tmpbuff,".quit"))
{
break;
}
}
close(sockfd);
return 0;
}




