网络编程是Linux系统编程的核心内容之一,而Socket是实现网络通信的基石。无论是Web服务器、即时通讯工具还是分布式系统,都依赖于Socket进行数据传输。本文将深入讲解Socket编程的基本概念,并通过C语言实现一个完整的TCP客户端-服务器通信示例,帮助初学者掌握网络编程的核心技能。
Socket(套接字)是网络通信的端点,用于在不同主机或同一主机的不同进程之间传输数据。它封装了底层网络协议的细节,提供统一的编程接口。
类比:Socket类似于电话插座,应用程序通过“插拔”Socket实现通信。
TCP(传输控制协议):
面向连接,可靠传输(数据不丢失、不重复)。
适合文件传输、网页访问等场景。
UDP(用户数据报协议):
无连接,高效但不可靠。
适合视频流、实时游戏等场景。
创建Socket → 2. 绑定地址 → 3. 监听连接 → 4. 接受连接 → 5. 通信 → 6. 关闭连接
创建Socket → 2. 连接服务器 → 3. 通信 → 4. 关闭连接
函数名 | 作用 | 服务器/客户端 |
---|---|---|
socket() |
创建Socket | 两者 |
bind() |
绑定IP和端口 | 服务器 |
listen() |
监听连接请求 | 服务器 |
accept() |
接受客户端连接 | 服务器 |
connect() |
连接服务器 | 客户端 |
send()/recv() |
发送/接收数据 | 两者 |
close() |
关闭Socket | 两者 |
sockaddr_in
(IPv4地址结构):struct sockaddr_in {
sa_family_t sin_family; // 地址族,如AF_INET
in_port_t sin_port; // 端口号(网络字节序)
struct in_addr sin_addr; // IP地址
};
struct in_addr {
uint32_t s_addr; // 32位IPv4地址(网络字节序)
};
#include
#include
#include
#include
#include
#include
#define PORT 8080
#define MAX_BUFFER 1024
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[MAX_BUFFER] = {0};
char *response = "Hello from server!";
// 1. 创建Socket
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 2. 绑定地址
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY; // 监听所有网卡
address.sin_port = htons(PORT); // 端口转为网络字节序
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 3. 监听连接
if (listen(server_fd, 3) < 0) {
perror("listen failed");
exit(EXIT_FAILURE);
}
printf("Server listening on port %d...\n", PORT);
// 4. 接受连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("accept failed");
exit(EXIT_FAILURE);
}
// 5. 通信
read(new_socket, buffer, MAX_BUFFER);
printf("Client message: %s\n", buffer);
send(new_socket, response, strlen(response), 0);
printf("Response sent\n");
// 6. 关闭连接
close(new_socket);
close(server_fd);
return 0;
}
socket(AF_INET, SOCK_STREAM, 0)
:
AF_INET
:IPv4协议族。
SOCK_STREAM
:TCP协议。
INADDR_ANY
:服务器监听所有可用网络接口。
htons(PORT)
:将端口号转换为网络字节序(大端模式)。
#include
#include
#include
#include
#include
#include
#include
#define PORT 8080
#define MAX_BUFFER 1024
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
char *message = "Hello from client!";
char buffer[MAX_BUFFER] = {0};
// 1. 创建Socket
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// 将IP地址从字符串转换为网络格式
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
perror("invalid address");
exit(EXIT_FAILURE);
}
// 2. 连接服务器
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("connection failed");
exit(EXIT_FAILURE);
}
// 3. 通信
send(sock, message, strlen(message), 0);
printf("Message sent to server\n");
read(sock, buffer, MAX_BUFFER);
printf("Server response: %s\n", buffer);
// 4. 关闭连接
close(sock);
return 0;
}
inet_pton()
:将点分十进制的IP地址(如127.0.0.1
)转换为二进制格式。
connect()
:发起与服务器的连接请求。
# 编译服务器
gcc server.c -o server
# 编译客户端
gcc client.c -o client
启动服务器:
./server
Server listening on port 8080...
2.启动客户端:
./client
Message sent to server
Server response: Hello from server!
Client message: Hello from client!
Response sent
多客户端支持:使用多线程或select()
函数处理并发连接。
数据协议设计:定义应用层协议(如HTTP、自定义协议)规范数据格式。
错误恢复:添加超时机制和重传逻辑增强鲁棒性。
Socket是网络通信的基石,TCP提供可靠的双向字节流传输。
服务器核心步骤:创建→绑定→监听→接受→通信→关闭。
客户端核心步骤:创建→连接→通信→关闭。
通过本文的学习,读者应能掌握Socket编程的基本原理,并能够实现简单的TCP客户端-服务器通信。下一步可探索UDP通信或构建高性能服务器模型(如Epoll)。