欢迎来到Linux网络编程实战教程!本文将带你从零开始,使用TCP Socket实现一个简单的远程命令执行系统。通过本教程,你将掌握Socket编程实战的核心技能,包括socket创建、绑定、监听、连接、数据传输以及命令执行与结果返回。无论你是初学者还是有一定经验的开发者,都能从中获得实用的知识和代码。

确保你有一台Linux机器(如Ubuntu/CentOS),并安装gcc编译器:sudo apt install gcc 或 sudo yum install gcc。你需要了解基本的TCP/IP协议栈,以及socket API函数:socket(), bind(), listen(), accept(), connect(), send(), recv()。
服务端负责监听端口,接受客户端连接,然后循环接收命令,通过popen()执行并将输出返回给客户端。我们采用“长度+数据”的格式解决TCP粘包问题:先发送4字节(网络字节序)的数据长度,再发送实际数据。
#include #include #include #include #include #include #include #include #define PORT 8888#define BUFFER_SIZE 4096// 发送全部数据(处理短写)int send_all(int sockfd, const char *buf, int len) { int total = 0; while (total < len) { int n = send(sockfd, buf + total, len - total, 0); if (n == -1) break; total += n; } return total;}// 接收指定长度数据int recv_all(int sockfd, char *buf, int len) { int total = 0; while (total < len) { int n = recv(sockfd, buf + total, len - total, 0); if (n <= 0) break; total += n; } return total;}int main() { int server_fd, client_fd; struct sockaddr_in server_addr, client_addr; socklen_t client_len = sizeof(client_addr); char cmd[BUFFER_SIZE]; char result[BUFFER_SIZE]; FILE *fp; // 创建socket if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } // 设置端口复用 int opt = 1; if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { perror("setsockopt"); exit(1); } // 绑定地址和端口 memset(&server_addr, 0, sizeof(server_addr)); 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)) == -1) { perror("bind"); exit(1); } // 监听 if (listen(server_fd, 5) == -1) { perror("listen"); exit(1); } printf("[服务端] 启动成功,监听端口 %d...\n", PORT); while (1) { // 接受客户端连接 client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len); if (client_fd == -1) { perror("accept"); continue; } printf("[客户端] %s:%d 已连接\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); // 循环处理命令 while (1) { // 先接收命令长度(4字节,网络字节序) int cmd_len; if (recv_all(client_fd, (char*)&cmd_len, 4) != 4) { printf("[客户端] 断开连接\n"); break; } cmd_len = ntohl(cmd_len); // 转换为主机字节序 // 接收命令内容 if (cmd_len >= BUFFER_SIZE) { printf("[警告] 命令过长,丢弃\n"); // 跳过数据 char tmp[1024]; while (cmd_len > 0) { int n = recv(client_fd, tmp, sizeof(tmp), 0); if (n <= 0) break; cmd_len -= n; } continue; } if (recv_all(client_fd, cmd, cmd_len) != cmd_len) { perror("recv cmd"); break; } cmd[cmd_len] = "\0"; printf("[执行] 命令: %s\n", cmd); // 执行命令 fp = popen(cmd, "r"); if (fp == NULL) { strcpy(result, "popen 失败"); } else { int total = 0; while (fgets(result + total, BUFFER_SIZE - total, fp) != NULL) { total = strlen(result); if (total >= BUFFER_SIZE - 1) break; } pclose(fp); } // 准备发送结果,格式:长度(4字节)+ 数据 int result_len = strlen(result); int net_len = htonl(result_len); send_all(client_fd, (char*)&net_len, 4); send_all(client_fd, result, result_len); memset(result, 0, BUFFER_SIZE); // 清空缓冲区 } close(client_fd); } close(server_fd); return 0;} 客户端连接服务端,从标准输入读取命令,发送给服务端,并接收执行结果打印。
#include #include #include #include #include #include #include #define SERVER_IP "127.0.0.1"#define PORT 8888#define BUFFER_SIZE 4096int send_all(int sockfd, const char *buf, int len) { int total = 0; while (total < len) { int n = send(sockfd, buf + total, len - total, 0); if (n == -1) break; total += n; } return total;}int recv_all(int sockfd, char *buf, int len) { int total = 0; while (total < len) { int n = recv(sockfd, buf + total, len - total, 0); if (n <= 0) break; total += n; } return total;}int main() { int sockfd; struct sockaddr_in server_addr; char cmd[BUFFER_SIZE]; char result[BUFFER_SIZE]; // 创建socket if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } // 设置服务器地址 memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT); if (inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr) <= 0) { perror("inet_pton"); exit(1); } // 连接服务器 if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) { perror("connect"); exit(1); } printf("[客户端] 已连接到服务器 %s:%d\n", SERVER_IP, PORT); while (1) { printf("> "); fflush(stdout); if (fgets(cmd, BUFFER_SIZE, stdin) == NULL) break; cmd[strcspn(cmd, "\n")] = "\0"; // 去掉换行符 if (strlen(cmd) == 0) continue; if (strcmp(cmd, "exit") == 0) break; // 发送命令长度(4字节,网络字节序) int cmd_len = strlen(cmd); int net_len = htonl(cmd_len); send_all(sockfd, (char*)&net_len, 4); send_all(sockfd, cmd, cmd_len); // 接收结果长度 int result_len; if (recv_all(sockfd, (char*)&result_len, 4) != 4) { printf("[错误] 服务器断开\n"); break; } result_len = ntohl(result_len); // 接收结果数据 if (result_len >= BUFFER_SIZE) { printf("[警告] 结果过长,截断显示\n"); recv_all(sockfd, result, BUFFER_SIZE-1); result[BUFFER_SIZE-1] = "\0"; // 跳过剩余数据 char tmp[1024]; int remain = result_len - (BUFFER_SIZE-1); while (remain > 0) { int n = recv(sockfd, tmp, sizeof(tmp), 0); if (n <= 0) break; remain -= n; } } else { recv_all(sockfd, result, result_len); result[result_len] = "\0"; } printf("%s\n", result); } close(sockfd); return 0;} 打开两个终端,分别编译服务端和客户端:
gcc server.c -o servergcc client.c -o client先运行服务端:./server,再运行客户端:./client。在客户端输入命令(如ls、pwd),即可看到远程执行结果。输入exit退出客户端。
popen直接执行用户输入存在注入风险,建议对命令进行白名单过滤或使用参数化方式(如execve系列)。fork()或多线程为每个客户端创建独立服务进程/线程。通过本教程,你亲手实现了一个基于TCP Socket的远程命令执行系统,深入理解了Linux网络编程的核心API和Socket编程实战技巧。你可以在此基础上扩展功能,如添加用户认证、加密传输、并发处理等,打造更强大的远程管理工具。希望本文能成为你网络编程之路的坚实起点!
本文关键词:Linux网络编程,TCP Socket,远程命令执行,Socket编程实战
本文由主机测评网于2026-03-01发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://www.vpshk.cn/20260327857.html