【Linux C学习笔记】4.4 网络编程基础学习总结
📖今日学习:OSI七层模型、TCP/IP四层模型、IP地址分类、虚拟机网络模式、字节序转换、socket套接字、UDP编程、TCP编程。
🔍文章大纲
- 网络基础概念
- OSI七层模型与TCP/IP四层模型
- IP地址、子网掩码、IP地址分类
- 虚拟机网络模式(NAT / 桥接模式)
- 网络字节序(大端、小端)转换函数
- UDP套接字编程(socket、sendto、recvfrom、bind)
- TCP套接字编程(socket、connect、listen、accept、send、recv)
- ✨学习重点汇总
- ⚠️易错点&踩坑记录
- 📝今日学习小结
1. 网络基础概念
协议:通信双方预先约定好的一套通信标准,规定数据格式、交互规则。
OSI七层参考模型
| 层级 | 名称 | 作用 |
|---|---|---|
| 7 | 应用层 | 业务数据内容 |
| 6 | 表示层 | 数据加密、解密、格式转换 |
| 5 | 会话层 | 建立/维持会话连接 |
| 4 | 传输层 | 负责端到端传输(TCP/UDP) |
| 3 | 网络层 | 路由选择,IP寻址 |
| 2 | 数据链路层 | 局域网MAC帧传输 |
| 1 | 物理层 | 网线、网卡等硬件电气信号 |
TCP/IP四层实际模型(Linux网络编程使用)
| 层级 | 包含协议 |
|---|---|
| 应用层 | HTTP、HTTPS、FTP、DNS、TFTP、SMTP |
| 传输层 | TCP、UDP |
| 网络层 | IP、ARP、RARP |
| 网络接口层 | 网卡驱动、MAC通信 |
- UDP:无连接,不可靠,资源开销小,只管发送,不确认对方是否收到。
- TCP:面向连接,可靠传输;通信前三次握手建立连接;结束四次挥手断开;具备确认重传、拥塞控制、滑动窗口。
2. IP地址相关
IP地址 = 网络位 + 主机位
- 网络位:标识属于哪一个局域网
- 主机位:局域网内主机编号
- 网段地址:主机位全部为0
- 广播地址:主机位全部为1,向局域网所有主机发送数据
IP地址分类
| 类别 | 地址范围 | 默认子网掩码 | 用途 | 私有网段 |
|---|---|---|---|---|
| A类 | 1.0.0.0‑126.255.255.255 | 255.0.0.0 | 超大型网络 | 10.0.0.0/8 |
| B类 | 128.0.0.0‑191.255.255.255 | 255.255.0.0 | 大中型网络 | 172.16‑31段 |
| C类 | 192.0.0.0‑223.255.255.255 | 255.255.255.0 | 中小型局域网 | 192.168.x.x |
| D类 | 224‑239 | --- | 组播 | --- |
| E类 | 240‑255 | --- | 实验保留 | --- |
子网掩码 :用来区分IP地址中的网络位与主机位;二进制1代表网络位,0代表主机位。
示例:192.168.0.175/24等价子网掩码255.255.255.0。
MAC地址
网卡出厂自带唯一硬件地址,局域网内部依靠MAC地址完成帧通信;跨网段依靠IP地址路由。
3. 虚拟机两种网络模式
-
NAT模式
- Windows主机上网,虚拟机就可以上网;虚拟机使用虚拟IP。
- 虚拟机可以访问外网,外部局域网设备无法主动访问虚拟机。
- 适合开发调试上网,不适合做服务器。
-
桥接模式
- 虚拟机和物理主机处于同一个局域网,分配独立真实局域网IP。
- 虚拟机既可以访问外网,局域网其他设备也可以访问虚拟机,可以作为服务器。
- 会占用局域网一个IP地址。
修改网卡配置文件
/etc/network/interfaces设置dhcp自动获取IP;ping www.baidu.com测试网络连通。
4. 网络字节序
网络通信统一使用大端字节序 :低地址存放高位数据。
本地PC一般为小端模式:低地址存放低位数据。
字节序转换函数:
c
//主机短整型 → 网络大端
uint16_t htons(uint16_t hostshort);
//主机长整型 → 网络大端
uint32_t htonl(uint32_t hostlong);
//网络大端 → 主机短整型
uint16_t ntohs(uint16_t netshort);
//网络大端 → 主机长整型
uint32_t ntohl(uint32_t netlong);
IP地址字符串与网络二进制转换:
c
in_addr_t inet_addr(const char *cp); //点分字符串ip转网络大端整数
char *inet_ntoa(struct in_addr in); //网络二进制ip转回点分字符串
IPv4套接字地址结构体sockaddr_in
c
struct sockaddr_in {
sa_family_t sin_family; /* 协议族 AF_INET */
in_port_t sin_port; /* 端口号(网络字节序) */
struct in_addr sin_addr; /* ip地址(网络字节序) */
};
5. UDP编程(用户数据报)
UDP特点:无连接,发送不需要建立连接;每个数据包独立;不可靠;适合视频、广播。
核心API
c
//1. 创建套接字
int socket(int domain, int type, int protocol);
// domain: AF_INET ipv4
// type: SOCK_DGRAM UDP数据报
// protocol: 填0默认协议
//2. 发送数据
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
//3. 接收数据
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
//4. 绑定IP端口到套接字
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
bind():将本机IP+端口绑定到socket;服务器一般需要bind;客户端一般不需要bind,操作系统自动分配临时端口。- 端口号:1‑1023系统保留端口;自定义程序建议使用1024‑65535。
UDP客户端流程:socket → sendto / recvfrom → close
UDP服务器流程:socket → bind → recvfrom / sendto → close
6. TCP编程(流式套接字 SOCK_STREAM)
TCP特点:面向连接;三次握手建立连接;四次挥手断开连接;可靠传输;字节流。
核心API
c
//创建tcp套接字
int socket(int domain, int type, int protocol);
//type: SOCK_STREAM
//客户端:向服务器发起连接
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//服务器:开启监听
int listen(int sockfd, int sockfd, int backlog);
//backlog:未处理连接请求队列最大长度
//服务器:接受客户端连接,返回新通信fd
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//TCP发送数据
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
//TCP接收数据
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
recv返回值说明:
0:成功收到字节数
- 0:对端已经关闭连接
- -1:出错
TCP客户端流程 :socket → connect → send / recv → close
TCP服务器流程:socket → bind → listen → accept → send/recv → close
注意:
accept返回新的文件描述符专门和客户端通信;listen的fd只用来监听连接,不收发业务数据。
✨学习重点
- 分清OSI七层模型与实际使用的TCP/IP四层模型;分清TCP与UDP的特性差异。
- IP地址、子网掩码作用;A/B/C/D/E五类IP划分;私有IP概念。
- NAT模式与桥接模式虚拟机网络区别:NAT不能被外部访问,桥接可以做服务器。
- 网络通信一律使用大端字节序 ;必须掌握
htons / ntohs端口字节序转换,忘记转换通信完全异常。 - UDP:无连接,使用
sendto/recvfrom收发,服务器必须bind绑定端口。 - TCP:面向连接,三次握手建立连接;
listen开启监听;accept返回新通信fd;recv返回0代表对方关闭socket。 - sockaddr_in结构体:
sin_port端口必须网络字节序,sin_addr.s_addrIP网络字节序。 - bind作用:绑定本机IP+端口到套接字;服务器一般bind;客户端操作系统自动分配临时端口,可不bind。
⚠️易错点&踩坑记录
- 端口忘记htons字节序转换,直接填数字,端口错乱,无法通信,高频错误。
- IP地址直接赋值点分字符串,没有使用
inet_addr转为网络二进制,程序运行异常。 - TCP中混淆监听socket fd 和 accept返回的通信fd;用listen的fd调用send/recv,直接出错。
- recv返回值判断错误:没有判断返回0,对方关闭连接后程序还继续recv,逻辑异常。
- bind绑定别人机器的IP地址,bind失败;bind只能绑定本机网卡拥有的IP。
- 同一个端口没有释放,程序重复启动bind报地址已被占用。
- UDP不要使用send/recv,UDP必须使用sendto、recvfrom,需要传入对端地址结构体。
- 虚拟机NAT模式下,外部主机无法访问虚拟机的服务器程序,需要切换桥接模式。
- listen的backlog不是最大客户端连接数,是未完成连接队列的长度。
- sockaddr_in强转问题:API参数需要
struct sockaddr*,定义sockaddr_in之后强制类型转换传入,类型不匹配编译告警。 - 不要使用1‑1023端口,属于系统知名端口,容易权限不足bind失败。
📝今日学习小结
今天学习Linux网络编程基础4.4章节,掌握网络协议分层模型、IP地址分类、子网掩码,理解NAT与桥接两种虚拟机网络模式。
- 网络传输统一使用大端字节序 ,主机小端需要调用
htons完成转换,是网络编程最容易踩坑点。 - UDP无连接,使用
sendto/recvfrom;服务器必须bind绑定端口,客户端可以不用bind。 - TCP面向连接,三次握手建立连接;服务器流程
socket‑bind‑listen‑accept,accept返回新fd专门与客户端通信;recv返回0代表对端关闭连接。