在网络编程领域,C 语言凭借其高效性和对底层的良好控制能力,成为实现网络通信的常用语言。Socket 编程是 C 语言实现网络通信的关键技术,它提供了一种机制,使不同主机上的进程能够进行数据交换,广泛应用于网络服务器开发、分布式系统等领域。
Socket 基础概念
- Socket 类型:常见的 Socket 类型有两种,即流式套接字(SOCK_STREAM)和数据报套接字(SOCK_DGRAM)。流式套接字基于 TCP 协议,提供可靠的、面向连接的字节流服务,适用于对数据准确性要求高、数据量大的场景,如文件传输。例如:
int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0) { perror("Socket 创建失败"); exit(1);}这里 socket 函数创建了一个流式套接字,AF_INET 表示使用 IPv4 地址族。数据报套接字基于 UDP 协议,提供无连接的、不可靠的数据传输服务,适用于对实时性要求高但对数据准确性要求相对较低的场景,如视频流传输。创建数据报套接字示例:
int sockfd = socket(AF_INET, SOCK_DUDP, 0);if (sockfd < 0) { perror("Socket 创建失败"); exit(1);}- Socket 地址结构:在网络通信中,需要使用地址结构来标识通信的端点。对于 IPv4,常用的地址结构是 sockaddr_in。例如,绑定一个 Socket 到指定地址和端口:
struct sockaddr_in servaddr;memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(8080);servaddr.sin_addr.s_addr = INADDR_ANY;if (bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { perror("绑定失败"); close(sockfd); exit(1);}这里设置了服务器地址结构,将端口号转换为网络字节序,并使用 INADDR_ANY 表示绑定到所有可用的网络接口。bind 函数将 Socket 与指定的地址和端口绑定。
TCP 网络编程
- 服务器端编程:TCP 服务器端通常需要经历创建 Socket、绑定地址、监听连接、接受连接和数据传输等步骤。例如:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <arpa/inet.h>#include <sys/socket.h>#define PORT 8080#define MAXLINE 1024int main() { int sockfd; char buffer[MAXLINE]; struct sockaddr_in servaddr, cliaddr; sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("Socket 创建失败"); exit(EXIT_FAILURE); } memset(&servaddr, 0, sizeof(servaddr)); memset(&cliaddr, 0, sizeof(cliaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = INADDR_ANY; servaddr.sin_port = htons(PORT); if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { perror("绑定失败"); close(sockfd); exit(EXIT_FAILURE); } if (listen(sockfd, 10) < 0) { perror("监听失败"); close(sockfd); exit(EXIT_FAILURE); } socklen_t len = sizeof(cliaddr); int connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &len); if (connfd < 0) { perror("接受连接失败"); close(sockfd); exit(EXIT_FAILURE); } int n = read(connfd, buffer, sizeof(buffer)); buffer[n] = '\0'; printf("收到的消息: %s\n", buffer); char *resp = "消息已收到"; write(connfd, resp, strlen(resp)); close(connfd); close(sockfd); return 0;}此代码创建了一个 TCP 服务器,监听指定端口,接受客户端连接,读取客户端发送的消息并回复确认信息。
2. 客户端编程:TCP 客户端需要创建 Socket、连接服务器和进行数据传输。例如:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <arpa/inet.h>#include <sys/socket.h>#define PORT 8080#define MAXLINE 1024#define SERVER_IP "127.0.0.1"int main() { int sockfd; char buffer[MAXLINE]; struct sockaddr_in servaddr; sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("Socket 创建失败"); exit(EXIT_FAILURE); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(PORT); servaddr.sin_addr.s_addr = inet_addr(SERVER_IP); if (connect(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { perror("连接失败"); close(sockfd); exit(EXIT_FAILURE); } char *msg = "Hello, Server!"; write(sockfd, msg, strlen(msg)); int n = read(sockfd, buffer, sizeof(buffer)); buffer[n] = '\0'; printf("收到的回复: %s\n", buffer); close(sockfd); return 0;}该客户端代码创建 Socket 后连接到指定服务器,发送消息并接收服务器的回复。
UDP 网络编程
- 服务器端编程:UDP 服务器端主要进行创建 Socket、绑定地址和接收 / 发送数据操作。例如:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <arpa/inet.h>#include <sys/socket.h>#define PORT 8080#define MAXLINE 1024int main() { int sockfd; char buffer[MAXLINE]; struct sockaddr_in servaddr, cliaddr; sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { perror("Socket 创建失败"); exit(EXIT_FAILURE); } memset(&servaddr, 0, sizeof(servaddr)); memset(&cliaddr, 0, sizeof(cliaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = INADDR_ANY; servaddr.sin_port = htons(PORT); if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { perror("绑定失败"); close(sockfd); exit(EXIT_FAILURE); } socklen_t len = sizeof(cliaddr); int n = recvfrom(sockfd, (char *)buffer, MAXLINE, MSG_WAITALL, (struct sockaddr *)&cliaddr, &len); buffer[n] = '\0'; printf("收到的消息: %s\n", buffer); char *resp = "消息已收到"; sendto(sockfd, (const char *)resp, strlen(resp), MSG_/confirm/i, (const struct sockaddr *)&cliaddr, len); close(sockfd); return 0;}此 UDP 服务器代码接收客户端发送的消息,并回复确认信息。
2. 客户端编程:UDP 客户端创建 Socket 后直接向服务器发送数据并接收回复。例如:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <arpa/inet.h>#include <sys/socket.h>#define PORT 8080#define MAXLINE 1024#define SERVER_IP "127.0.0.1"int main() { int sockfd; char buffer[MAXLINE]; struct sockaddr_in servaddr; sockfd = socket(AF_INET, SOCK_DUDP, 0); if (sockfd < 0) { perror("Socket 创建失败"); exit(EXIT_FAILURE); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(PORT); servaddr.sin_addr.s_addr = inet_addr(SERVER_IP); char *msg = "Hello, Server!"; sendto(sockfd, (const char *)msg, strlen(msg), MSG_/confirm/i, (const struct sockaddr *)&servaddr, sizeof(servaddr)); socklen_t len = sizeof(servaddr); int n = recvfrom(sockfd, (char *)buffer, MAXLINE, MSG_WAITALL, (const struct sockaddr *)&servaddr, &len); buffer[n] = '\0'; printf("收到的回复: %s\n", buffer); close(sockfd); return 0;}该 UDP 客户端代码向服务器发送消息并接收服务器的回复。
应用场景
- 网络服务器开发:如 Web 服务器、文件服务器等,通过 Socket 编程实现与客户端的高效通信,处理大量的并发请求。
- 实时通信应用:像即时通讯软件、在线游戏等,利用 UDP 的实时性和 TCP 的可靠性,实现消息的快速传递和数据的准确传输。
每天坚持学习一点点,不求有回报,只愿可以丰富自己!!!

