Linux系统下的socket是应用层与传输层之间的抽象接口,基于socket可以实现不同主机甚至同一主机内不同进程之间的网络通信,其中TCP协议的socket通信是最常用的可靠传输场景,能够实现服务器和客户端之间的稳定对话。
socket通信的基本流程
TCP协议的服务器和客户端对话遵循固定的交互流程,核心步骤可以分为以下几个部分:
- 服务端先创建socket实例,绑定对应的IP地址和端口号
- 服务端开启监听,等待客户端的连接请求
- 客户端创建socket实例,向服务端的地址和端口发起连接
- 服务端接受客户端的连接请求,生成用于和该客户端通信的新socket
- 双方通过新生成的socket进行数据的收发,实现对话
- 通信结束后双方关闭对应的socket资源
服务端实现代码
以下是基于C语言实现的TCP服务端代码,能够接收客户端发送的消息并回复响应:
#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 8080
#define BUFFER_SIZE 1024
int main() {
int server_fd, client_fd;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
char buffer[BUFFER_SIZE] = {0};
// 创建socket,使用IPv4、TCP协议
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
perror("socket创建失败");
exit(EXIT_FAILURE);
}
// 配置服务端地址
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY; // 绑定所有本地网卡
server_addr.sin_port = htons(PORT); // 端口转换为网络字节序
// 绑定地址和端口
if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
perror("地址绑定失败");
close(server_fd);
exit(EXIT_FAILURE);
}
// 开启监听,最大等待连接数为5
if (listen(server_fd, 5) < 0) {
perror("监听开启失败");
close(server_fd);
exit(EXIT_FAILURE);
}
printf("服务端已启动,监听端口:%dn", PORT);
// 接受客户端连接
client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
if (client_fd < 0) {
perror("接受连接失败");
close(server_fd);
exit(EXIT_FAILURE);
}
printf("客户端已连接,地址:%s,端口:%dn", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
// 接收客户端消息
int read_len = read(client_fd, buffer, BUFFER_SIZE);
if (read_len > 0) {
printf("收到客户端消息:%sn", buffer);
// 给客户端回复消息
char* reply = "服务端已收到你的消息";
write(client_fd, reply, strlen(reply));
}
// 关闭socket资源
close(client_fd);
close(server_fd);
return 0;
}
客户端实现代码
对应的TCP客户端代码,能够向服务端发送消息并接收响应:
#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 PORT 8080
#define BUFFER_SIZE 1024
int main() {
int client_fd;
struct sockaddr_in server_addr;
char buffer[BUFFER_SIZE] = {0};
// 创建socket
client_fd = socket(AF_INET, SOCK_STREAM, 0);
if (client_fd < 0) {
perror("socket创建失败");
exit(EXIT_FAILURE);
}
// 配置服务端地址
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
// 转换IP地址格式
if (inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr) <= 0) {
perror("IP地址转换失败");
close(client_fd);
exit(EXIT_FAILURE);
}
// 连接服务端
if (connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
perror("连接服务端失败");
close(client_fd);
exit(EXIT_FAILURE);
}
printf("已成功连接到服务端n");
// 向服务端发送消息
char* message = "你好,我是客户端";
write(client_fd, message, strlen(message));
printf("已发送消息:%sn", message);
// 接收服务端回复
int read_len = read(client_fd, buffer, BUFFER_SIZE);
if (read_len > 0) {
printf("收到服务端回复:%sn", buffer);
}
// 关闭socket资源
close(client_fd);
return 0;
}
代码编译与运行步骤
完成代码编写后,可以按照以下步骤编译运行:
- 将服务端代码保存为
server.c,客户端代码保存为client.c - 使用gcc编译两个文件:
gcc server.c -o server,gcc client.c -o client - 先启动服务端程序:
./server - 再启动客户端程序:
./client,即可看到双方的对话输出
关键注意事项
在实际开发中需要注意以下几点:
- 端口号建议使用1024以上的数值,避免和系统预留端口冲突
- 网络字节序和主机字节序的转换需要使用
htons、ntohs等函数,否则会出现端口识别错误 - 数据收发后要及时检查返回值,避免通信异常导致的程序错误
- 多客户端场景下需要配合进程或线程处理每个客户端的连接,避免单个客户端阻塞整个服务端
linux_socketserver_client_communicationC_socket_programmingtcp_protocol修改时间:2026-06-22 22:36:58