提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
提示:这里可以添加本文要记录的大概内容:
socket远程命令通信简单实现
内核版本5.10
cli端连接上ser端后,ser发送给cli端命令执行。
cli支持命令:
CMD_TYPE_TEST :测试,字符串通信
CMD_TYPE_EXEC:执行程序
CMD_TYPE_DOWNLOAD:下载文件
CMD_TYPE_UPLOAD:上传文件
上传和下载暂未实现。
--
提示:以下是本篇文章正文内容,下面案例可供参考
一、代码示例?
socket_cmd.h
c
#ifndef __SOCKET_CMD_H__
#define __SOCKET_CMD_H__
typedef enum {
CMD_TYPE_TEST = 0x1100,
CMD_TYPE_EXEC,
CMD_TYPE_DOWNLOAD,
CMD_TYPE_UPLOAD,
CMD_TYPE_MAX,
} cmd_type_t;
typedef enum {
OP_TYPE_TEST = 0x2100,
OP_TYPE_REQ,
OP_TYPE_REQ_WAIT,
OP_TYPE_ACK,
OP_TYPE_FAIL,
OP_TYPE_MAX,
} op_type_t;
struct s_cmd
{
int cmd;
int op;
char msg[256];
};
#endif
socket_cmd_ser.c
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include "socket_cmd.h"
#define SERVER_IP "127.0.0.1" // 服务器的 IP 地址
#define SERVER_PORT 8080 // 服务器的端口号
int ser_sock_create(char * addr, int port, int listen_num)
{
char s_ip[16] = {0};
int sockfd;
int clifd;
struct sockaddr_in server_addr = {0};
struct sockaddr_in client_addr = {0};
char cmd_buf[512] = {0};
int ret = 0;
int addr_len = 0;
if(addr == NULL || port > 65535 || port < 0 || listen_num <= 0 || listen_num > 1024)
{
return -1;
}
printf("addr = %s, port = %d, listen_num = %d\n", addr, port, listen_num);
memcpy(s_ip, addr, strnlen(addr, 16));
// 创建套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket creation failed");
return -1;
}
// Set the SO_REUSEADDR option
int optval = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) {
perror("Setsockopt failed");
close(sockfd);
return 1;
}
// 设置客户端地址信息
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port); // 客户端绑定的端口号
server_addr.sin_addr.s_addr = inet_addr(s_ip); // 绑定所有可用接口
// 绑定套接字到客户端地址
if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("bind failed");
close(sockfd);
return -1;
}
addr_len = sizeof(client_addr);
// 获取并打印绑定的 IP 地址和端口号
if (getsockname(sockfd, (struct sockaddr *)&server_addr, &addr_len) == -1) {
perror("getsockname failed");
close(sockfd);
return -1;
}
char ip_str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &server_addr.sin_addr, ip_str, sizeof(ip_str));
printf("ser bind %s:%d\n", ip_str, ntohs(server_addr.sin_port));
// 开始监听连接
if (listen(sockfd, listen_num) < 0) {
perror("Listen failed");
return -1;
}
clifd = accept(sockfd, NULL, NULL);
if (clifd < 0) {
perror("Accept failed");
return -1;
}
// 这里可以添加发送和接收数据的代码
while(1)
{
memset(cmd_buf, 0, sizeof(cmd_buf));
struct s_cmd cmd = {0};
cmd.cmd = CMD_TYPE_TEST;
cmd.op = OP_TYPE_TEST;
memcpy(cmd.msg, "hello cmd", strnlen( "hello cmd", 128));
memcpy(cmd_buf, &cmd, sizeof(cmd));
ssize_t send_received = send(clifd, cmd_buf, sizeof(cmd) , MSG_NOSIGNAL);
//ssize_t send_received = write(clifd, cmd_buf, sizeof(cmd_buf) - 1);
printf("send_received = %d\n", send_received);
if (send_received == -1) {
if (errno == EPIPE) {
printf("Client disconnected.\n");
} else {
perror("Send failed");
}
close(clifd);
return -1;
}
usleep(3* 1000 * 1000);
}
// 关闭套接字
close(sockfd);
}
int main() {
int sockfd;
ser_sock_create("0.0.0.0", 9090, 1);
return 0;
}
socket_cmd_cli.c
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "socket_cmd.h"
#define SERVER_IP "127.0.0.1" // 服务器的 IP 地址
#define SERVER_PORT 8080 // 服务器的端口号
#define CLIENT_PORT 19091 // 客户端绑定的端口号
#define MAX_ARGS 10
int do_str_execvp(char * exec_cmd)
{
char *args[MAX_ARGS];
int int arg_count = 0;
char cmd_copy[256] = {0};
strncpy(cmd_copy, exec_cmd,strnlen(exec_cmd, 256));
char *token = strtok(cmd_copy, " "); // 默认以空格分隔
// 提取命令和参数
while (token != NULL && arg_count < MAX_ARGS - 1) {
args[arg_count++] = token;
token = strtok(NULL, " ");
}
args[arg_count] = NULL; // execvp 的参数数组必须以 NULL 结尾
// 使用 execvp 执行命令
if (execvp(args[0], args) == -1) {
perror("execvp failed");
exit(EXIT_FAILURE);
}
// 如果 execvp 成功,下面的代码将不会执行
return 0;
}
int do_cmd_exec(char* exec_cmd)
{
int pid_t pid;
if(NULL == exec_cmd)
{
return -1;
}
pid = fork()
if(pid < 0)
{
printf("fork failed\n");
return -1;
}else if(pid == 0)
{
// 子进程
do_str_execvp(exec_cmd);
}else
{
// 父进程
}
}
int cli_cmd_dispatch(struct s_cmd * cmd)
{
struct s_cmd* tmp_cmd = NULL;
if(cmd == NULL)
{
return -1;
}
tmp_cmd = malloc(sizeof(struct s_cmd));
if(tmp_cmd == NULL)
{
return -1;
}
memcpy(tmp_cmd, cmd, sizeof(struct s_cmd));
switch(tmp_cmd->cmd)
{
case CMD_TYPE_TEST:
break;
case CMD_TYPE_EXEC:
break;
case CMD_TYPE_DOWNLOAD:
break;
case CMD_TYPE_UPLOAD:
break;
default:
break;
}
free(tmp_cmd);
return 0;
}
int cli_check_cmd_valid(struct s_cmd * cmd)
{
if(cmd == NULL)
{
return -1;
}
return 0;
}
int cli_sock_create(char * seraddr, int serport, char * cliaddr, int cliport)
{
char s_ip[16] = {0};
char c_ip[16] = {0};
int sockfd;
struct sockaddr_in server_addr = {0};
struct sockaddr_in client_addr = {0};
char cmd_buf[512] = {0};
int ret = 0;
int addr_len = 0;
if(seraddr == NULL || serport > 65535 || serport < 0 || cliport < 0 || cliport > 65535)
{
return -1;
}
if(cliaddr == NULL)
{
memcpy(c_ip, "0.0.0.0", strnlen("0.0.0.0", 16));
}else
{
memcpy(c_ip, cliaddr, strnlen(cliaddr, 16));
}
memcpy(s_ip, seraddr, strnlen(seraddr, 16));
// 创建套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// 设置客户端地址信息
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(CLIENT_PORT); // 客户端绑定的端口号
client_addr.sin_addr.s_addr = inet_addr(c_ip); // 绑定所有可用接口
// 绑定套接字到客户端地址
if (bind(sockfd, (struct sockaddr *)&client_addr, sizeof(client_addr)) < 0) {
perror("bind failed");
close(sockfd);
exit(EXIT_FAILURE);
}
addr_len = sizeof(client_addr);
// 获取并打印绑定的 IP 地址和端口号
if (getsockname(sockfd, (struct sockaddr *)&client_addr, &addr_len) == -1) {
perror("getsockname failed");
close(sockfd);
exit(EXIT_FAILURE);
}
char ip_str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &client_addr.sin_addr, ip_str, sizeof(ip_str));
printf("cli bind %s:%d\n", ip_str, ntohs(client_addr.sin_port));
// 设置服务器地址信息
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(serport);
server_addr.sin_addr.s_addr = inet_addr(s_ip);
// 连接到服务器
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("connection to server failed");
close(sockfd);
exit(EXIT_FAILURE);
}
printf("connetct to ser %s:%d\n", s_ip, serport);
// 这里可以添加发送和接收数据的代码
while(1)
{
struct s_cmd cmd = {0};
memset(cmd_buf, 0, sizeof(cmd_buf));
ssize_t bytes_received = recv(sockfd, cmd_buf, sizeof(struct s_cmd), 0);
if (bytes_received < 0) {
perror("recv failed");
close(sockfd);
return -1;
} else if (bytes_received == 0) {
printf("ser closed\n");
close(sockfd);
return 0;
}
memcpy(&cmd, cmd_buf, sizeof(struct s_cmd));
printf("bytes_received = %d, cmd.cmd = 0x%x, cmd.op = 0x%x, cmd.msg = %s\n", bytes_received, cmd.cmd, cmd.op, cmd.msg);
if(cli_check_cmd_valid(&cmd) == 0)
{
cli_cmd_dispatch(&cmd);
}
}
// 关闭套接字
close(sockfd);
}
int main() {
int sockfd;
cli_sock_create("127.0.0.1", 9090, NULL, 0);
return 0;
}
Makefile
c
all:
gcc socket_cmd_cli.c -o socket_cmd_cli -g
gcc socket_cmd_ser.c -o socket_cmd_ser -g
clean:
rm -f socket_cmd_cli socket_cmd_ser
总结
socket远程命令通信简单实现,目标支持命令:测试,字符串通信,执行程序,下载文件,上传文件。