
C语言必背100代码系列文章目录
核心内容:Hello World、条件判断、循环结构、数组基础、函数定义等。
核心内容:数组排序、字符串处理、多维数组、字符匹配、内存拷贝等。
核心内容:指针运算、动态内存分配、结构体指针、函数指针、内存泄漏检测等。
核心内容:阶乘递归、汉诺塔、分治算法、回溯算法、动态规划基础等。
核心内容:链表、栈、队列、二叉树、哈希表、图的基本操作。
核心内容:文本文件读写、二进制文件操作、日志管理、CSV/JSON解析等。
核心内容:快速幂、素数测试、进制转换、矩阵运算、蒙特卡洛模拟等。
核心内容:进程控制、线程同步、信号处理、套接字编程、系统调用封装等。
核心内容:TCP/UDP通信、HTTP请求、WebSocket、SSL/TLS加密、网络抓包等。
第五篇:数据结构实现

想系统掌握C语言网络开发?这篇硬核教程带你从零构建TCP/UDP通信框架,破解HTTP协议实现原理!通过10个实战案例+源码级解析,深度揭秘Socket编程、多线程服务器、广播通信等核心技术。从三次握手细节到字节序转换陷阱,从简易聊天室到HTTP客户端开发,本文涵盖网络编程全链路。无论你是刚接触Socket的萌新,还是想优化网络模块的工程师,这篇覆盖TCP粘包处理、UDP广播实战、端口扫描原理等干货的进阶指南,都能让你的网络开发能力实现质的突破!
1. TCP客户端(连接服务器并发送数据)
c
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <arpa/inet.h> | |
| #define PORT 8080 | |
| #define BUFFER_SIZE 1024 | |
| int main() { | |
| int sock = 0; | |
| struct sockaddr_in serv_addr; | |
| char buffer[BUFFER_SIZE] = {0}; | |
| // 创建Socket | |
| if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { | |
| perror("Socket creation error"); | |
| return -1; | |
| } | |
| serv_addr.sin_family = AF_INET; | |
| serv_addr.sin_port = htons(PORT); | |
| // 转换IP地址(示例:127.0.0.1) | |
| if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) { | |
| perror("Invalid address/Address not supported"); | |
| return -1; | |
| } | |
| // 连接服务器 | |
| if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { | |
| perror("Connection Failed"); | |
| return -1; | |
| } | |
| // 发送数据 | |
| const char *message = "Hello from client!"; | |
| send(sock, message, strlen(message), 0); | |
| printf("Message sent: %s\n", message); | |
| // 接收响应 | |
| read(sock, buffer, BUFFER_SIZE); | |
| printf("Server response: %s\n", buffer); | |
| close(sock); | |
| return 0; | |
| } |
- 详细注释:
- socket():创建Socket(AF_INET表示IPv4,SOCK_STREAM表示TCP)。
- inet_pton():将点分十进制IP转为二进制格式。
- connect():阻塞式连接,超时需设置SO_RCVTIMEO选项。
- 应用场景:客户端工具(如HTTP请求、即时通讯)。
- 常见问题:
- 服务器未启动导致connect()失败。
- 缓冲区溢出(需检查read()返回值)。
2. TCP服务器(多线程处理客户端)
c
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <arpa/inet.h> | |
| #include <pthread.h> | |
| #define PORT 8080 | |
| #define BUFFER_SIZE 1024 | |
| void *handleClient(void *arg) { | |
| int clientSock = *(int *)arg; | |
| char buffer[BUFFER_SIZE] = {0}; | |
| read(clientSock, buffer, BUFFER_SIZE); | |
| printf("Received: %s\n", buffer); | |
| const char *response = "Hello from server!"; | |
| send(clientSock, response, strlen(response), 0); | |
| close(clientSock); | |
| return NULL; | |
| } | |
| int main() { | |
| int serverSock, clientSock; | |
| struct sockaddr_in address; | |
| int opt = 1; | |
| int addrlen = sizeof(address); | |
| // 创建Socket | |
| if ((serverSock = socket(AF_INET, SOCK_STREAM, 0)) == 0) { | |
| perror("Socket failed"); | |
| exit(EXIT_FAILURE); | |
| } | |
| // 设置Socket选项(允许地址重用) | |
| if (setsockopt(serverSock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { | |
| perror("setsockopt"); | |
| exit(EXIT_FAILURE); | |
| } | |
| address.sin_family = AF_INET; | |
| address.sin_addr.s_addr = INADDR_ANY; | |
| address.sin_port = htons(PORT); | |
| // 绑定Socket | |
| if (bind(serverSock, (struct sockaddr *)&address, sizeof(address)) < 0) { | |
| perror("Bind failed"); | |
| exit(EXIT_FAILURE); | |
| } | |
| // 监听 | |
| if (listen(serverSock, 3) < 0) { | |
| perror("Listen"); | |
| exit(EXIT_FAILURE); | |
| } | |
| printf("Server listening on port %d...\n", PORT); | |
| while (1) { | |
| // 接受客户端连接 | |
| if ((clientSock = accept(serverSock, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { | |
| perror("Accept"); | |
| continue; | |
| } | |
| printf("Client connected: %s:%d\n", | |
| inet_ntoa(address.sin_addr), ntohs(address.sin_port)); | |
| // 创建线程处理客户端 | |
| pthread_t tid; | |
| if (pthread_create(&tid, NULL, handleClient, &clientSock) < 0) { | |
| perror("Thread creation failed"); | |
| close(clientSock); | |
| continue; | |
| } | |
| pthread_detach(tid); // 分离线程,避免资源泄漏 | |
| } | |
| return 0; | |
| } |
- 详细注释:
- setsockopt():设置SO_REUSEADDR避免端口占用。
- pthread_create():为每个客户端创建独立线程。
- pthread_detach():线程退出时自动释放资源。
- 应用场景:Web服务器、聊天室。
- 扩展知识:
- 使用线程池(如pthread_pool)优化性能。
- 添加SSL/TLS加密(如OpenSSL库)。
3. UDP客户端(发送广播消息)
c
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <arpa/inet.h> | |
| #define PORT 8888 | |
| #define BUFFER_SIZE 1024 | |
| int main() { | |
| int sock = 0; | |
| struct sockaddr_in serv_addr; | |
| char buffer[BUFFER_SIZE] = {0}; | |
| // 创建UDP Socket | |
| if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { | |
| perror("Socket creation error"); | |
| return -1; | |
| } | |
| // 启用广播选项 | |
| int broadcastEnable = 1; | |
| if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable)) < 0) { | |
| perror("setsockopt (SO_BROADCAST)"); | |
| return -1; | |
| } | |
| serv_addr.sin_family = AF_INET; | |
| serv_addr.sin_port = htons(PORT); | |
| serv_addr.sin_addr.s_addr = inet_addr("255.255.255.255"); // 广播地址 | |
| // 发送广播消息 | |
| const char *message = "This is a broadcast message!"; | |
| sendto(sock, message, strlen(message), 0, | |
| (const struct sockaddr *)&serv_addr, sizeof(serv_addr)); | |
| printf("Broadcast message sent: %s\n", message); | |
| close(sock); | |
| return 0; | |
| } |
- 详细注释:
- SOCK_DGRAM:UDP协议。
- SO_BROADCAST:允许发送广播包。
- 255.255.255.255:本地广播地址(需在子网内有效)。
- 应用场景:局域网设备发现(如打印机、游戏服务器)。
- 常见问题:
- 路由器可能禁止广播包转发。
- 防火墙可能拦截UDP端口。
4. UDP服务器(接收广播消息)
c
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <arpa/inet.h> | |
| #define PORT 8888 | |
| #define BUFFER_SIZE 1024 | |
| int main() { | |
| int sock = 0; | |
| struct sockaddr_in serv_addr, cli_addr; | |
| char buffer[BUFFER_SIZE] = {0}; | |
| socklen_t addrlen = sizeof(cli_addr); | |
| // 创建UDP Socket | |
| if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { | |
| perror("Socket creation error"); | |
| return -1; | |
| } | |
| serv_addr.sin_family = AF_INET; | |
| serv_addr.sin_addr.s_addr = INADDR_ANY; | |
| serv_addr.sin_port = htons(PORT); | |
| // 绑定Socket | |
| if (bind(sock, (const struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { | |
| perror("Bind failed"); | |
| return -1; | |
| } | |
| printf("UDP server listening on port %d...\n", PORT); | |
| while (1) { | |
| // 接收消息 | |
| int n = recvfrom(sock, buffer, BUFFER_SIZE, 0, | |
| (struct sockaddr *)&cli_addr, &addrlen); | |
| buffer[n] = '\0'; | |
| printf("Received from %s:%d: %s\n", | |
| inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port), buffer); | |
| } | |
| close(sock); | |
| return 0; | |
| } |
- 详细注释:
- recvfrom():接收UDP数据包并返回发送方地址。
- INADDR_ANY:监听所有网络接口。
- 应用场景:网络监控、实时数据采集。
- 扩展知识:
- 多播(Multicast)替代广播(减少网络负担)。
- 使用epoll(Linux)处理高并发UDP连接。
5. HTTP GET请求(Socket实现)
c
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <arpa/inet.h> | |
| #define PORT 80 | |
| #define BUFFER_SIZE 4096 | |
| int main() { | |
| int sock = 0; | |
| struct sockaddr_in serv_addr; | |
| char buffer[BUFFER_SIZE] = {0}; | |
| // 创建Socket | |
| if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { | |
| perror("Socket creation error"); | |
| return -1; | |
| } | |
| serv_addr.sin_family = AF_INET; | |
| serv_addr.sin_port = htons(PORT); | |
| // 解析域名(示例:example.com) | |
| struct hostent *host = gethostbyname("example.com"); | |
| if (host == NULL) { | |
| perror("Host not found"); | |
| return -1; | |
| } | |
| memcpy(&serv_addr.sin_addr, host->h_addr, host->h_length); | |
| // 连接服务器 | |
| if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { | |
| perror("Connection Failed"); | |
| return -1; | |
| } | |
| // 发送HTTP GET请求 | |
| const char *request = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"; | |
| send(sock, request, strlen(request), 0); | |
| // 接收响应 | |
| int bytesRead; | |
| while ((bytesRead = read(sock, buffer, BUFFER_SIZE - 1)) > 0) { | |
| buffer[bytesRead] = '\0'; | |
| printf("%s", buffer); // 输出HTML内容 | |
| } | |
| close(sock); | |
| return 0; | |
| } |
- 详细注释:
- gethostbyname():解析域名(需包含<netdb.h>)。
- HTTP请求格式:GET / HTTP/1.1\r\nHost: ...\r\n\r\n。
- 应用场景:爬虫、API调用。
- 常见问题:
- 服务器可能关闭连接(需处理Connection: close)。
- 大响应需分块处理(避免缓冲区溢出)。
6. 域名解析(gethostbyname)
c
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <netdb.h> | |
| #include <arpa/inet.h> | |
| int main() { | |
| const char *hostname = "example.com"; | |
| struct hostent *host = gethostbyname(hostname); | |
| if (host == NULL) { | |
| perror("Host not found"); | |
| return 1; | |
| } | |
| printf("Official name: %s\n", host->h_name); | |
| printf("IP addresses:\n"); | |
| for (int i = 0; host->h_addr_list[i] != NULL; i++) { | |
| char *ip = inet_ntoa(*(struct in_addr *)host->h_addr_list[i]); | |
| printf(" %s\n", ip); // 输出:93.184.216.34等 | |
| } | |
| return 0; | |
| } |
- 详细注释:
- hostent结构体:包含主机名、别名列表、IP地址列表。
- h_addr_list:以NULL结尾的IP地址数组。
- 应用场景:网络工具开发、日志分析。
- 扩展知识:
- 使用getaddrinfo()替代(支持IPv6)。
- 异步DNS解析(如c-ares库)。
7. 端口扫描(基础实现)
c
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <arpa/inet.h> | |
| #include <netdb.h> | |
| #define START_PORT 1 | |
| #define END_PORT 1024 | |
| #define TIMEOUT 1 // 秒 | |
| int isPortOpen(const char *ip, int port) { | |
| int sock = socket(AF_INET, SOCK_STREAM, 0); | |
| if (sock < 0) return 0; | |
| struct sockaddr_in serv_addr; | |
| serv_addr.sin_family = AF_INET; | |
| serv_addr.sin_port = htons(port); | |
| inet_pton(AF_INET, ip, &serv_addr.sin_addr); | |
| // 设置超时 | |
| struct timeval tv; | |
| tv.tv_sec = TIMEOUT; | |
| tv.tv_usec = 0; | |
| setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); | |
| // 尝试连接 | |
| if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0) { | |
| close(sock); | |
| return 1; | |
| } | |
| close(sock); | |
| return 0; | |
| } | |
| int main() { | |
| const char *ip = "127.0.0.1"; | |
| printf("Scanning ports %d-%d on %s...\n", START_PORT, END_PORT, ip); | |
| for (int port = START_PORT; port <= END_PORT; port++) { | |
| if (isPortOpen(ip, port)) { | |
| printf("Port %d is open\n", port); | |
| } | |
| } | |
| return 0; | |
| } |
- 详细注释:
- SO_RCVTIMEO:设置连接超时。
- 扫描范围:1-1024(常见服务端口)。
- 应用场景:网络安全测试。
- 注意事项:
- 未经授权扫描可能违法。
- 需处理防火墙拦截(如RST包)。
8. 文件传输(TCP Socket)
c
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <arpa/inet.h> | |
| #define PORT 8080 | |
| #define BUFFER_SIZE 1024 | |
| void sendFile(int sock, const char *filename) { | |
| FILE *file = fopen(filename, "rb"); | |
| if (file == NULL) { | |
| perror("Failed to open file"); | |
| return; | |
| } | |
| char buffer[BUFFER_SIZE]; | |
| size_t bytesRead; | |
| while ((bytesRead = fread(buffer, 1, BUFFER_SIZE, file)) > 0) { | |
| send(sock, buffer, bytesRead, 0); | |
| } | |
| fclose(file); | |
| printf("File sent: %s\n", filename); | |
| } | |
| int main() { | |
| int sock = 0; | |
| struct sockaddr_in serv_addr; | |
| // 创建Socket | |
| if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { | |
| perror("Socket creation error"); | |
| return -1; | |
| } | |
| serv_addr.sin_family = AF_INET; | |
| serv_addr.sin_port = htons(PORT); | |
| inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr); | |
| // 连接服务器 | |
| if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { | |
| perror("Connection Failed"); | |
| return -1; | |
| } | |
| // 发送文件名 | |
| const char *filename = "test.txt"; | |
| send(sock, filename, strlen(filename), 0); | |
| // 发送文件内容 | |
| sendFile(sock, filename); | |
| close(sock); | |
| return 0; | |
| } |
- 详细注释:
- 先发送文件名,再传输文件内容。
- 需服务器端配合接收并保存文件。
- 扩展知识:
- 添加校验和(如MD5)验证文件完整性。
- 分块传输(支持大文件)。
9. 简单聊天室(TCP多客户端)
c
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <arpa/inet.h> | |
| #include <pthread.h> | |
| #define PORT 8080 | |
| #define MAX_CLIENTS 10 | |
| #define BUFFER_SIZE 1024 | |
| int clientSocks[MAX_CLIENTS] = {0}; | |
| void broadcastMessage(const char *message, int senderSock) { | |
| for (int i = 0; i < MAX_CLIENTS; i++) { | |
| if (clientSocks[i] != 0 && clientSocks[i] != senderSock) { | |
| send(clientSocks[i], message, strlen(message), 0); | |
| } | |
| } | |
| } | |
| void *handleClient(void *arg) { | |
| int clientSock = *(int *)arg; | |
| char buffer[BUFFER_SIZE] = {0}; | |
| int bytesRead; | |
| while ((bytesRead = read(clientSock, buffer, BUFFER_SIZE)) > 0) { | |
| buffer[bytesRead] = '\0'; | |
| printf("Client %d: %s", clientSock, buffer); | |
| char response[BUFFER_SIZE + 20]; | |
| snprintf(response, sizeof(response), "Client %d: %s", clientSock, buffer); | |
| broadcastMessage(response, clientSock); | |
| } | |
| // 客户端断开 | |
| printf("Client %d disconnected\n", clientSock); | |
| close(clientSock); | |
| for (int i = 0; i < MAX_CLIENTS; i++) { | |
| if (clientSocks[i] == clientSock) { | |
| clientSocks[i] = 0; | |
| break; | |
| } | |
| } | |
| return NULL; | |
| } | |
| int main() { | |
| int serverSock, clientSock; | |
| struct sockaddr_in address; | |
| int opt = 1; | |
| int addrlen = sizeof(address); | |
| // 创建Socket | |
| if ((serverSock = socket(AF_INET, SOCK_STREAM, 0)) == 0) { | |
| perror("Socket failed"); | |
| exit(EXIT_FAILURE); | |
| } | |
| if (setsockopt(serverSock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { | |
| perror("setsockopt"); | |
| exit(EXIT_FAILURE); | |
| } | |
| address.sin_family = AF_INET; | |
| address.sin_addr.s_addr = INADDR_ANY; | |
| address.sin_port = htons(PORT); | |
| if (bind(serverSock, (struct sockaddr *)&address, sizeof(address)) < 0) { | |
| perror("Bind failed"); | |
| exit(EXIT_FAILURE); | |
| } | |
| if (listen(serverSock, 3) < 0) { | |
| perror("Listen"); | |
| exit(EXIT_FAILURE); | |
| } | |
| printf("Chat server started on port %d...\n", PORT); | |
| while (1) { | |
| if ((clientSock = accept(serverSock, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { | |
| perror("Accept"); | |
| continue; | |
| } | |
| // 查找空闲槽位 | |
| int i; | |
| for (i = 0; i < MAX_CLIENTS; i++) { | |
| if (clientSocks[i] == 0) { | |
| clientSocks[i] = clientSock; | |
| break; | |
| } | |
| } | |
| if (i == MAX_CLIENTS) { | |
| printf("Max clients reached. Rejecting client %d\n", clientSock); | |
| close(clientSock); | |
| continue; | |
| } | |
| printf("New client connected: %d\n", clientSock); | |
| pthread_t tid; | |
| if (pthread_create(&tid, NULL, handleClient, &clientSock) < 0) { | |
| perror("Thread creation failed"); | |
| close(clientSock); | |
| continue; | |
| } | |
| pthread_detach(tid); | |
| } | |
| return 0; | |
| } |
- 详细注释:
- clientSocks数组:管理所有客户端连接。
- broadcastMessage():向其他客户端广播消息。
- 应用场景:实时通讯工具。
- 扩展知识:
- 添加用户认证(如用户名/密码)。
- 使用select/poll替代多线程(简化资源管理)。
10. 网络字节序转换
c
| #include <stdio.h> | |
| #include <arpa/inet.h> | |
| int main() { | |
| uint32_t hostValue = 0x12345678; | |
| uint32_t netValue = htonl(hostValue); // 主机序转网络序 | |
| printf("Host: 0x%08X, Network: 0x%08X\n", hostValue, netValue); | |
| uint32_t backToHost = ntohl(netValue); // 网络序转主机序 | |
| printf("Back to host: 0x%08X\n", backToHost); | |
| // 16位整数转换 | |
| uint16_t hostShort = 0x1234; | |
| uint16_t netShort = htons(hostShort); | |
| printf("Host short: 0x%04X, Network short: 0x%04X\n", hostShort, netShort); | |
| return 0; | |
| } |
- 详细注释:
- htonl()/ntohl():32位整数转换。
- htons()/ntohs():16位整数转换。
- 应用场景:跨平台网络协议实现。
- 常见问题:
- 忽略字节序导致数据解析错误。
- 浮点数需自定义序列化(如IEEE 754标准)。
扩展知识
- 高性能网络编程:
- 使用epoll(Linux)或kqueue(macOS/BSD)处理高并发。
- 零拷贝技术(如sendfile)。
- 安全建议:
- 验证输入数据(防止缓冲区溢出)。
- 使用加密协议(如TLS)。
- 协议设计:
- 自定义二进制协议(如<length><data>格式)。
- 使用现有协议(如HTTP/2、WebSocket)。

💡注意:本文所介绍的软件及功能均基于公开信息整理,仅供用户参考。在使用任何软件时,请务必遵守相关法律法规及软件使用协议。同时,本文不涉及任何商业推广或引流行为,仅为用户提供一个了解和使用该工具的渠道。
你在生活中时遇到了哪些问题?你是如何解决的?欢迎在评论区分享你的经验和心得!
希望这篇文章能够满足您的需求,如果您有任何修改意见或需要进一步的帮助,请随时告诉我!
感谢各位支持,可以关注我的个人主页,找到你所需要的宝贝。
博文入口:https://blog.youkuaiyun.com/Start_mswin 复制到【浏览器】打开即可,宝贝入口:https://pan.quark.cn/s/71742b5e7629
作者郑重声明,本文内容为本人原创文章,纯净无利益纠葛,如有不妥之处,请及时联系修改或删除。诚邀各位读者秉持理性态度交流,共筑和谐讨论氛围~





980





