linux下c编程:单实例运行服务器程序

博客介绍了在Linux环境下的功能实现。一是在shell中运行客户端程序可临时获取root权限;二是使用文件锁,借助UNIX Domain Socket IPC让服务器程序单实例运行,并提及对应的客户端程序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

功能实现:shell中运行客户端程序临时获取root权限。
在linux下只允许一个服务器进程接收信息
使用文件锁,使服务器程序单实例运行(UNIX Domain Socket IPC):

/* server.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stddef.h>
#include <sys/un.h>
#include <fcntl.h>
#include <error.h>
#include <libgen.h>
#include <dirent.h>
#include <errno.h>

#define MAXLINE 1024

 //返回当前可执行文件名
char *currentExeName()
{
    long pid;
    char full_name[MAXLINE],proc_name[MAXLINE];
    bzero(full_name,MAXLINE);
    bzero(proc_name,MAXLINE);
    int fd;
    pid = getpid();
    printf("pid = %ld\n",pid);
    sprintf(full_name, "/proc/%ld/cmdline", pid);
    if (access(full_name, F_OK) == 0) {
        fd = open(full_name, O_RDONLY);
        if (fd == -1){
            perror("fd open failed...\n");
            return 0;
        }
        read(fd, proc_name, MAXLINE);
        close(fd);
    }
    else {
        return 0;
    }
    printf("proc_name = %s\n",proc_name);
    char self_proc_name[512];
    bzero(self_proc_name,512);
    char *p = proc_name;
    int pt = 0;
    while(*p != ' ' && *p != '\0') {
        self_proc_name[pt] = *p;
        p++;
        pt++;
    }
    printf("self_proc_name = %s\n",self_proc_name);
    char self_final_name[512];
    bzero(self_final_name,512);
    char *sfn;
    sfn = basename(self_proc_name);
    strncpy(self_final_name,sfn,sizeof(sfn));
    printf("self_final_name = %s\n",self_final_name);
    return sfn;
}

int runSingleInstance()
{
    // 获取当前可执行文件名
    char *processName = currentExeName();
    if (processName == NULL)
    {
        printf("processName is null...\n");
        return 0;
    }
    // 打开或创建一个文件
    char filePath[MAXLINE];
    bzero(filePath,sizeof(MAXLINE));
    sprintf(filePath,"/var/run/%s.pid",processName);
    int fd = open(filePath, O_RDWR | O_CREAT, 0666);
    if (fd < 0)
    {
        perror("Open file failed, error...\n");
        return 0;
    }
    // 将该文件锁定
    // 锁定后的文件将不能够再次锁定
    struct flock fl;
    fl.l_type = F_WRLCK; // 写文件锁定
    fl.l_start = 0;
    fl.l_whence = SEEK_SET;
    fl.l_len = 0;
    int ret = fcntl(fd, F_SETLK, &fl);
    if (ret < 0)
    {
        if (errno == EACCES || errno == EAGAIN)
        {
            printf("%s already locked, error: %s\n", filePath, strerror(errno));
            close(fd);
            return 0;
        }
    }
    // 锁定文件后,将该进程的pid写入文件
    char buf[16] = {'\0'};
    sprintf(buf, "%d", getpid());
    ftruncate(fd, 0);
    ret = write(fd, buf, strlen(buf));
    if (ret < 0)
    {
        printf("Write file failed, file: %s, error: %s\n", filePath, strerror(errno));
        close(fd);
        return 0;
    }
    // 函数返回时不需要调用close(fd)
    // 不然文件锁将失效
    // 程序退出后kernel会自动close
    return 1;
}

int main(void){
    //单实例,判断服务器是否已经在运行 
    if (!runSingleInstance()) {
        perror("server is already running...\n");
        return 0;
    }else{
        printf("server is not already running...\n");
    }
    listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if(listenfd < 0){
        perror ("can not create listen socket ...\n");
        exit(1);
    }
    servaddr.sun_family = AF_UNIX;
    strcpy(servaddr.sun_path, "foo.socket");
    servaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen(servaddr.sun_path);
    bind(listenfd, (struct sockaddr *)&servaddr,  sizeof(servaddr));
    //修改服务端socket权限
    chmod ("foo.socket", 0666);
    //监听端口
    tmp = listen(listenfd, 20);
    if(tmp < 0){
        perror ("listen failed...\n");
        close(listenfd);
        exit(1);
    }
    printf("Accepting connections ...\n");
    while (1) {
        cliaddr_len = sizeof(cliaddr);
        //接收连接申请
        connfd = accept(listenfd,(struct sockaddr *)&cliaddr, &cliaddr_len);
        if (connfd < 0){
            perror("accept failed...\n");
            continue;
        }
        pid = fork();
        if (pid < 0) {
            perror("fork failed");
            exit(-1);
        }
        if (pid > 0){
            printf ("parent pid = %d, ppid = %d\n",getpid(),getppid());
        }else{
            printf ("child pid = %d, ppid = %d\n",getpid(),getppid());
            while(1) {
                bzero(buf,MAXLINE);
                tmp = read(connfd, buf, MAXLINE);
                if (tmp == -1){
                    break;
                }else if(tmp == buf[0] && tmp>2){
                    printf("received:%s\n",&buf[2]);
                    if (buf[1] == 0){
                        FILE* fp = NULL;
                        fp = popen(&buf[2], "r");
                        if (!fp) {
                            perror("popen failed...\n");
                            exit(-1);
                        }
                        char t_buf[MAXLINE];
                        while ((tmp = fread(t_buf,1,sizeof(t_buf),fp))> 0)
                        {
                            write(connfd,t_buf,tmp);
                            bzero(t_buf,sizeof(t_buf));
                        }
                        write(connfd,t_buf,1);
                        pclose(fp);
                        }else if (buf[1] == 2){
                            // printf ("buf[1] = 2...buf[2] = %s\n",&buf[2]);
                            if (strncmp (&buf[2] , "cd ", 3) == 0) {
                                // printf ("strncmp (&buf[2] , cd, 3) == 0...buf[5]=%s\n",&buf[5]);
                                if (is_dir_exist(&buf[5])) {
                                    // printf ("is_dir_exist...\n");
                                    chdir(&buf[5]);
                                }
                                char t_buf[16];
                                bzero(t_buf, sizeof(t_buf));
                                write (connfd, t_buf, 1);   
                            }else{
                                break;
                            }
                        }else
                        {
                            break;
                        }       
                }else
                {
                    break;
                }  
            }
            close(connfd); 
            exit(1);
        }
        close(connfd);
    }
    close(listenfd);
    return 0;
}

//判断文件夹是否存在
int is_dir_exist (const char* dir) {
    if (dir == NULL) {
        return 0;
    } 
    if (opendir(dir) == NULL) {
        return 0;
    }
    return 1;
}


对应的客户端程序:

/* client.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stddef.h>
#include <sys/un.h>
#include <pwd.h>
#include <dirent.h>
// #define SERV_PORT 8000
#define CMD_BUFFER_SIZE 256
#define RET_BUFFER_SIZE 1024
int sockfd;

int main(int argc, char *argv[])
{
    struct sockaddr_un servaddr, cliaddr;
    int servaddr_size, cliaddr_size;
    int tmp;
    //创建socket
    sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if(sockfd < 0){
        perror("can't creat socket");
        return -1;
    } 
    cliaddr.sun_family = AF_UNIX;
    strcpy(cliaddr.sun_path, "roo.socket");
    cliaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen(cliaddr.sun_path);
    //绑定客户端socket
    bind(sockfd, (struct sockaddr *)&cliaddr, cliaddr_size);
    servaddr.sun_family = AF_UNIX;
    strcpy(servaddr.sun_path, "foo.socket");
    servaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen(servaddr.sun_path);
    //申请连接
    tmp = connect(sockfd, (struct sockaddr *)&servaddr,servaddr_size);
    if (tmp < 0) {
        perror("cannot connect server");
        close(sockfd);
        return -1;
    }
    char cmd_buff[CMD_BUFFER_SIZE];
    memset (cmd_buff, 0 , sizeof(cmd_buff));
    if (argc == 1) {
        if (geteuid() == 0) {
            setuid(0);
        }
        char path[256];
        int pos = 0;
        memset(path, 0, sizeof(path));
        getcwd(path, sizeof(path));
        sprintf(cmd_buff, "cd %s", path);
        tmp = send_command (cmd_buff, 2);
        while (1) {
            struct passwd *pwd;
            pwd = getpwuid(getuid());
            memset(path, 0, sizeof(path));
            getcwd(path, sizeof(path));
            printf("%s@cct_mode:%s $ ", pwd->pw_name, path);
            memset (cmd_buff, 0 , sizeof(cmd_buff));
            int ch;
            while (pos+2 < CMD_BUFFER_SIZE && (ch = getchar()) != '\n') {
                cmd_buff[pos++] = ch;
            }
            //后续添加处理间隔符代码
            if (strcmp (cmd_buff, "exit") == 0) {
                break;
            } else if (strncmp (cmd_buff, "cd ", 3) == 0) {
                if (is_dir_exist(&cmd_buff[3])) {
                    if (chdir(&cmd_buff[3]) == 0) {
                        tmp = send_command (cmd_buff, 2);
                    }
                }
            } else {
                tmp = send_command (cmd_buff, 0);
            }
            // memset (cmd_buff, 0 , sizeof(cmd_buff));
            pos = 0;
        }
    }else {
        int pos = 0;
        int i;
        for (i = 1; i < argc; i++) {
            if (pos + strlen(argv[i]) + 2 >= CMD_BUFFER_SIZE) {
                printf ("som_shell : error, command is too long......\n");
                return -1;
            }
            strcat(&cmd_buff[pos], argv[i]);
            pos += strlen(argv[i]);
            if (i < argc-1) {
                cmd_buff[pos] = ' ';
                pos++;
            }        
        }
        tmp = send_command (cmd_buff, 0);        
    }
    close(sockfd);
    return tmp;
}  
int is_dir_exist (const char* dir) {
    if (dir == NULL) {
        return 0;
    } 
    if (opendir(dir) == NULL) {
        return 0;
    }
    return 1;
}
/**
 * @brif    通过socket向server发送指令
 * @param   cmd 待发送指令
 * @param   type 指令类型     0:普通,   2:内建指令
 * @return  成功返回0,失败返回-1
 **/
 int send_command (char* cmd, int type) {
    int ret;
    char* send_buff;
    char ret_buff[RET_BUFFER_SIZE];
    int len = strlen(cmd) + 2;
    if (len > CMD_BUFFER_SIZE) {
        printf("error, command is too long......\n");
        return -1;
    } else {
        send_buff = malloc(len);
    }
    memset(ret_buff, 0, sizeof(ret_buff));
    memcpy (&send_buff[2], cmd, strlen(cmd));
    send_buff[0] = len;
    send_buff[1] = type;
    int n;
    n = write(sockfd, send_buff, len);
    printf("write return:%d\n",n);
    while ((ret = read(sockfd, ret_buff, sizeof(ret_buff))) > 0) {
        int i;
        for (i = 0; i<ret; i++) {
            putchar(ret_buff[i]);
        }
        //接收到终止符
        if (ret_buff[ret-1] == 0) {
            break;
        } 
        memset(ret_buff, 0, sizeof(ret_buff));
    }
    free(send_buff);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值