首页 > 其他分享 >socket远程命令通信简单实现

socket远程命令通信简单实现

时间:2024-09-13 19:24:19浏览次数:13  
标签:return addr int cmd 通信 sockfd TYPE 远程 socket

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

提示:这里可以添加本文要记录的大概内容:

socket远程命令通信简单实现
内核版本5.10
cli端连接上ser端后,ser发送给cli端命令执行。
cli支持命令:
CMD_TYPE_TEST :测试,字符串通信
CMD_TYPE_EXEC:执行程序
CMD_TYPE_DOWNLOAD:下载文件
CMD_TYPE_UPLOAD:上传文件

上传和下载暂未实现。

提示:以下是本篇文章正文内容,下面案例可供参考

一、代码示例?

socket_cmd.h

#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

#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

#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

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远程命令通信简单实现,目标支持命令:测试,字符串通信,执行程序,下载文件,上传文件。

标签:return,addr,int,cmd,通信,sockfd,TYPE,远程,socket
From: https://blog.csdn.net/qq_37077309/article/details/142217288

相关文章

  • ClickHouse的安装配置+DBeaver远程连接
    1、clickhouse的下载:先去clickhouse官网进行下载,继续往下翻找文档,将DBeaver也下载下来下载地址:https://packages.clickhouse.com/rpm/stable/下载这个四个rpm包 2、上传rmp文件到Linux中自己创建的一个clickhouse-install的文件夹,将这四个包存放进去3、开始安装1......
  • WebSocket1
    服务端开启websocket中间件//需要UseWebSockets,否则无法使用WebSocketapp.UseWebSockets(newWebSocketOptions(){KeepAliveInterval=TimeSpan.FromSeconds(60),});//处理websocket的中间件app.UseMiddleware<WebsocketMiddlware>();WebsocketMiddlwarepublic......
  • 为什么那么多开源软件都用netty来做网络通信编程框架?
     1、用netty来做网络通信编程框架而不是我们自己去基于JDKNIO来编程的好处有如下这些:(1)、netty支持常见的应用层协议(如:HTTP、FTP、DNS等),还可以支持自定义协议;(2)、netty可以自动解决网络编程当中的粘包与半包问题;(3)、netty还可以支持流量整形;(4)、netty对于网络通信当中......
  • RS232 串口服务器:传统通信的现代升级
    在现代通信技术的快速发展中,RS232串口服务器成为了连接传统设备与现代网络的关键桥梁。尽管RS232是一种较为古老的串行通信标准,但它在某些特定领域仍然发挥着不可替代的作用。本文将探讨RS232串口服务器如何实现传统通信的现代升级。RS232串口服务器是一种将RS232串行端口转换为网......
  • 多串口服务器:实现大规模设备通信的核心设备
    在物联网和工业自动化的浪潮中,设备之间的通信变得越来越频繁和复杂。为了应对这一挑战,多串口服务器成为了实现大规模设备通信的核心设备。它不仅能够提高数据传输的效率,还能够简化网络管理,为各种应用场景提供强大的支持。本文将探讨多串口服务器的重要性、关键特性以及在现代通信中......
  • 游戏客户端中的网络通信:使用Java实现实时数据交换| 网络通信|Java|游戏客户端
    在现代游戏开发中,Java作为一种强大的编程语言,广泛应用于游戏客户端的开发。Java的跨平台特性、丰富的类库以及强大的社区支持使其成为开发高性能、可维护的游戏客户端的理想选择。从简单的2D游戏到复杂的3D游戏,Java能够提供稳健的解决方案来应对各种挑战。本篇文章将深入探讨如何利......
  • 高效使用 gRPC 的配置技巧:深入解析 SocketsHttpHandler 设置
    在.NET中,gRPC是一个强大的远程过程调用(RPC)框架,能够高效地处理客户端和服务器之间的通信。为了最大化gRPC的性能,了解和优化SocketsHttpHandler的配置是关键。本文将介绍gRPC的使用技巧,并详细解释SocketsHttpHandler的重要配置项,并以表格的形式总结这些设置,以帮助开发者......
  • jenkins远程启动任务--启用远程触发构建
    一:前言在执行Jenkins的项目构建的时候,一般都是通过web管理界面中的”构建”来执行项目构建操作,但是除此之外我们还可以通过项目配置中的”构建触发器”来触发构建操作,其中”构建触发器”有一种方式是通过配置令牌远程触发项目构建。 二:设置用户token打开当前登录用户设置页面......
  • HttpClient 和 HttpGet 都设置了,setConnectTimeout 和 setReadTimeout/setSocketTimeo
    在使用ApacheHttpClient时,如果你分别在HttpClient和HttpGet(或其他请求对象)上都设置了setConnectTimeout和setReadTimeout(也叫setSocketTimeout),那么最终生效的配置是HttpGet(或请求对象)的配置优先,即请求对象上的超时设置会覆盖全局HttpClient的设置。具体规则说明:H......
  • 学习之git的远程仓库操作的常用命令
    1gitremote-v查看当前所有远程地址别名2gitremoteadd别名远程地址3gitpush别名分支(本地分支名称)推送本地分支到远程仓库4gitpull远程库别名远程分支别名拉取远程库分支(更新代码)5gitclone远程库地址克隆远程库代码克隆成功后本地会有......