一、TCP/IP 基础概念
这部分是面试的基础题,考察对网络基础的理解:
1. TCP/IP 协议栈分层
| TCP/IP 4 层模型 | 对应 OSI 7 层 | 核心协议 / 功能 |
|---|---|---|
| 应用层 | 应用层 + 表示层 + 会话层 | HTTP/FTP/Telnet,定义应用交互规则 |
| 传输层 | 传输层 | TCP/UDP,端到端数据传输(端口标识) |
| 网络层 | 网络层 | IP/ICMP/ARP,跨网络路由(IP 地址标识) |
系统梳理了 TCP/IP 网络基础与 C/C++ Socket 编程的核心知识点。内容涵盖 TCP/IP 协议栈分层、TCP 与 UDP 的区别、三次握手与四次挥手机制、TIME_WAIT 状态及优化方案。重点讲解了 Socket 编程流程,包括服务端与客户端代码示例、字节序转换、地址转换及 IO 多路复用技术(select/poll/epoll)。此外,还总结了 TCP 粘包处理、超时设置、并发模型选择等常见面试题与解决方案,适合准备后端开发或网络编程面试的开发者参考。
这部分是面试的基础题,考察对网络基础的理解:
| TCP/IP 4 层模型 | 对应 OSI 7 层 | 核心协议 / 功能 |
|---|---|---|
| 应用层 | 应用层 + 表示层 + 会话层 | HTTP/FTP/Telnet,定义应用交互规则 |
| 传输层 | 传输层 | TCP/UDP,端到端数据传输(端口标识) |
| 网络层 | 网络层 | IP/ICMP/ARP,跨网络路由(IP 地址标识) |
| 链路层 | 数据链路层 + 物理层 | 以太网 / PPP,局域网内帧传输(MAC 地址) |
| 特性 | TCP | UDP |
|---|---|---|
| 连接性 | 面向连接(三次握手) | 无连接 |
| 可靠性 | 可靠(确认 / 重传 / 排序) | 不可靠(无确认) |
| 传输方式 | 面向字节流 | 面向数据报 |
| 拥塞 / 流量控制 | 支持(滑动窗口 / 拥塞控制) | 不支持 |
| 头部开销 | 20-60 字节 | 8 字节 |
| 适用场景 | 文件传输 / HTTP / 邮件 | 视频 / 语音 / 直播 / 游戏 |
这部分是考察深度的核心,常问'为什么'和'过程':
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8888
#define BUF_SIZE 1024
int main() {
// 1. 创建 socket(文件描述符)
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd == -1) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 设置 SO_REUSEADDR,解决 TIME_WAIT 占用端口
int opt = 1;
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
// 2. 绑定 IP 和端口
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // IPv4
server_addr.sin_addr.s_addr = INADDR_ANY; // 监听所有网卡
server_addr.sin_port = htons(PORT); // 端口转换(主机序→网络序)
if (bind(listen_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
perror("bind failed");
close(listen_fd);
exit(EXIT_FAILURE);
}
// 3. 监听连接(半连接队列大小设为 5)
if (listen(listen_fd, 5) == -1) {
perror("listen failed");
close(listen_fd);
exit(EXIT_FAILURE);
}
printf("Server listening on port %d...\n", PORT);
// 4. 接受客户端连接(阻塞)
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int conn_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &client_len);
if (conn_fd == -1) {
perror("accept failed");
close(listen_fd);
exit(EXIT_FAILURE);
}
printf("Client connected: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
// 5. 收发数据(回显)
char buf[BUF_SIZE];
ssize_t recv_len;
while ((recv_len = recv(conn_fd, buf, BUF_SIZE-1, 0)) > 0) {
buf[recv_len] = '\0';
printf("Received from client: %s\n", buf);
send(conn_fd, buf, recv_len, 0); // 回显数据
}
// 6. 关闭连接
close(conn_fd);
close(listen_fd);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 8888
#define BUF_SIZE 1024
int main() {
// 1. 创建 socket
int client_fd = socket(AF_INET, SOCK_STREAM, 0);
if (client_fd == -1) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 2. 连接服务端
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
server_addr.sin_port = htons(SERVER_PORT);
if (connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
perror("connect failed");
close(client_fd);
exit(EXIT_FAILURE);
}
// 3. 发送数据
char buf[BUF_SIZE];
printf("Enter message to send: ");
fgets(buf, BUF_SIZE, stdin);
send(client_fd, buf, strlen(buf)-1, 0); // 去掉 fgets 的换行符
// 4. 接收回显数据
ssize_t recv_len = recv(client_fd, buf, BUF_SIZE-1, 0);
if (recv_len > 0) {
buf[recv_len] = '\0';
printf("Received from server: %s\n", buf);
}
// 5. 关闭连接
close(client_fd);
return 0;
}
htons():主机序 → 网络序(短整型,如端口);htonl():主机序 → 网络序(长整型,如 IP);ntohs()/ntohl():反向转换。inet_addr("127.0.0.1")(字符串→IP)、inet_ntoa(in_addr)(IP→字符串);inet_pton()/inet_ntop()(支持 IPv6,更安全)。| 模型 | 原理 | 缺点 | 优点 |
|---|---|---|---|
| select | 监听 fd_set 集合,轮询检查 | 上限 FD_SETSIZE(默认 1024)、需重置集合 | 跨平台 |
| poll | 监听 pollfd 数组,轮询检查 | 轮询效率低 | 无 fd 数量上限 |
| epoll | 红黑树 + 就绪链表,事件驱动 | 仅 Linux 支持 | 无 fd 上限、无需轮询、高性能 |
epoll 核心考点:
epoll_create()、epoll_ctl()(添加 / 修改 / 删除事件)、epoll_wait()(等待事件)。connect()/recv()/send()默认阻塞,需设置超时;setsockopt() 设置 SO_RCVTIMEO/SO_SNDTIMEO:struct timeval timeout;
timeout.tv_sec = 5; // 5 秒超时
timeout.tv_usec = 0;
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
fork(),父子进程共享 fd(需关闭多余 fd),处理僵尸进程(waitpid());pthread_create(),注意线程安全(如 fd 操作加锁);epoll(高性能,单进程处理上万连接)。
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online