Linux共享内存示例,使用信号量同步

1、shm_test1.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stddef.h>
#include <errno.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/socket.h>

#define SEM_KEY     100
#define SHM_KEY     101
#define TOTAL_SEM   10
#define UNIX_DOMAIN "/tmp/unix_sock"

typedef struct shared_use {
    int pktlen;
    unsigned char pkt[1528];
} shared_use_t;

static unsigned char ucast_pkt[] = {
  0x00, 0xd0, 0xf8, 0x00, 0x99, 0x22, 0x00, 0x00,
  0x00, 0x01, 0x01, 0x07, 0x08, 0x06, 0x00, 0x01,
  0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xbc, 0x30,
  0x00, 0x00, 0x00, 0x01, 0x01, 0x07, 0xc0, 0xa8,
  0xcc, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xc0, 0xa8, 0xcc, 0x64, 0x01, 0x02, 0x03, 0x04,
  0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
  0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14};

static int sem_id = 0;
static int com_fd = 0;
static void *shm = NULL;

/* 获取信号量资源 */
static int semaphore_v(void)
{
    struct sembuf sem_b;

    sem_b.sem_num = 0;
    sem_b.sem_op = 1;
    sem_b.sem_flg = SEM_UNDO;
    if (semop(sem_id, &sem_b, 1) == -1) {
        return -1;
    }

    return 0;
}

/* 释放信号量资源 */
static int semaphore_p(void)
{
    struct sembuf sem_b;

    sem_b.sem_num = 0;
    sem_b.sem_op = -1;
    sem_b.sem_flg = SEM_UNDO;
    if (semop(sem_id, &sem_b, 1) == -1) {
        return -1;
    }

    return 0;
}

/* 初始化信号量 */
static int semaphore_init(void)
{
    union semun sem_union;

    sem_id = semget((key_t)SEM_KEY, 1, 0666 | IPC_CREAT);
    if (sem_id == -1) {
        return -1;
    }

    sem_union.val = 1;
    if (semctl(sem_id, 0, SETVAL, sem_union) == -1) {
        return -1;
    }

    return 0;
}

/* 初始化共享内存 */
static int sharemmy_init(void)
{
    int shmid;

    /* 创建共享内存区域块 */
    shmid = shmget((key_t)SHM_KEY, sizeof(shared_use_t), 0666 | IPC_CREAT);
    if (shmid == -1) {
        return shmid;
    }

    /* 将本进程的虚拟内存映射到共享内存 */
    shm = shmat(shmid, (void *)0, 0);
    if (shm == (void *)-1) {
        return -1;
    }

    return shmid;
}

static int sharemmy_destroy(int shmid, void *shm)
{
    int rv;

    /* 删除本进程与共享内存的映射 */
    rv = shmdt(shm);
    if (rv == -1) {
        return rv;
    }

    /* 删除创建的共享内存块 */
    rv = shmctl(shmid, IPC_RMID, 0);
    if (rv == -1) {
        return rv;
    }

    return 0;
}

static int domain_server(void)
{
    int rv;
    int listen_fd;
    socklen_t len;
    struct sockaddr_un srv_un;
    struct sockaddr_un clt_un;

    listen_fd = socket(PF_UNIX, SOCK_STREAM, 0);
    if (listen_fd < 0) {
        perror("socket: ");
        return -1;
    }

    memset(&srv_un, 0, sizeof(srv_un));
    srv_un.sun_family = AF_UNIX;
    strncpy(srv_un.sun_path, UNIX_DOMAIN, sizeof(srv_un.sun_path) - 1);
    unlink(UNIX_DOMAIN);
    rv = bind(listen_fd, (struct sockaddr *)&srv_un, sizeof(srv_un));
    if (rv < 0) {
        perror("bind: ");
        close(listen_fd);
        unlink(UNIX_DOMAIN);
        return -1;
    }

    rv = listen(listen_fd, 1);
    if (rv < 0) {
        perror("listen: ");
        close(listen_fd);
        unlink(UNIX_DOMAIN);
        return -1;
    }

    len = sizeof(clt_un);
    while (1) {
        com_fd = accept(listen_fd, (struct sockaddr *)&clt_un, &len);
        if (errno == EINTR && com_fd == -1) {
            continue;
        }
        break;
    }

    return 0;
}

static void print_cmd_help(void)
{
    printf("CAMMAND NOT SUPPORT!.\n");
    printf("********** Help Info **********\n");
    printf("  1. Send -------- send a packet to commad.\n");
    printf("  2. Quit -------- quit the program.\n");
    printf("**********    End    **********\n");
}

static int shmwrite(void *shm)
{
    int rv;
    shared_use_t *shared;

    rv = semaphore_p();
    if (rv < 0) {
        return -1;
    }

    shared = (shared_use_t *)shm;
    shared->pktlen = sizeof(ucast_pkt);
    memcpy(shared->pkt, ucast_pkt, sizeof(ucast_pkt));

    rv = semaphore_v();
    if (rv < 0) {
        return -1;
    }

    return 0;
}

int main()
{
    int rv;
    int shmid;
    char cmd[10];

    rv = semaphore_init();
    if (rv < 0) {
        printf("Init a semaphore fail.\n");
        return 0;
    }

    shmid = sharemmy_init();
    if (shmid == -1) {
        printf("Init a share memory fail.\n");
        return 0;
    }

    rv = domain_server();
    if (rv < 0) {
        printf("Create domain server socket fail.\n");
        return 0;
    }
    printf("Server init success!\n");
    printf("\n");

    while (1) {
        memset(cmd, 0, sizeof(cmd));
        printf("Enter a command:");
        scanf("%s", cmd);
        if (cmd[9] != 0) {
            printf("Error : Command is too long, at most 9 char allowed!!!\n");
            continue;
        } else if (strstr(cmd, "send") != NULL || strstr(cmd, "Send") != NULL) {
            rv = shmwrite(shm);
            if (rv < 0) {
                printf("Write packet to share memory fail.\n");
                break;
            }
            rv = send(com_fd, cmd, sizeof(cmd), 0);
            if (rv < 0) {
                printf("Send command send fail.\n");
                continue;
            }
        } else if (strstr(cmd, "quit") != NULL || strstr(cmd, "Quit") != NULL) {
            printf("**********Stop Send Packet To Client.***********\n");
            rv = send(com_fd, cmd, sizeof(cmd), 0);
            if (rv < 0) {
                printf("Quit commadn send fail.\n");
            }
            break;
        } else {
            print_cmd_help();
        }
        printf("\n");
    }

    usleep(1000);
    rv = sharemmy_destroy(shmid, shm);
    if (rv < 0) {
        printf("Destroy share memory fail.\n");
        return 0;
    }

    return 1;
}

2、shm_test2.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/un.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/stat.h>
#include <sys/socket.h>

#define SEM_KEY     100
#define PRINT_TIMES 10
#define SHM_KEY     101
#define UNIX_DOMAIN "/tmp/unix_sock"

typedef struct shared_use {
    int pktlen;
    unsigned char pkt[1528];
} shared_use_t;

static int sem_id = 0;
static int connect_fd = 0;
static void *shm = NULL;

static int semaphore_v()
{
    struct sembuf sem_b;

    sem_b.sem_num = 0;
    sem_b.sem_op = 1;
    sem_b.sem_flg = SEM_UNDO;
    if (semop(sem_id, &sem_b, 1) == -1) {
        return -1;
    }

    return 0;
}

static int semaphore_p()
{
    struct sembuf sem_b;

    sem_b.sem_num = 0;
    sem_b.sem_op = -1;
    sem_b.sem_flg = SEM_UNDO;
    if (semop(sem_id, &sem_b, 1) == -1) {
        return -1;
    }

    return 0;
}

static int semaphore_init()
{
    sem_id = semget((key_t)SEM_KEY, 0, 0666 | IPC_CREAT);
    if (sem_id == -1) {
        return -1;
    }

    return 0;
}

static int sharemmy_init(void)
{
    int shmid;

    shmid = shmget((key_t)SHM_KEY, sizeof(shared_use_t), 0666 | IPC_CREAT);
    if (shmid == -1) {
        return shmid;
    }

    shm = shmat(shmid, (void *)0, 0);
    if (shm == (void *)-1) {
        return -1;
    }

    return shmid;
}

static int sharemmy_destroy(int shmid, void *shm)
{
    int rv;

    rv = shmdt(shm);
    if (rv == -1) {
        return rv;
    }

    return 0;
}

static int domain_client(void)
{
    int rv;
    struct sockaddr_un srv_un;

    connect_fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (connect_fd < 0) {
        perror("client socket: ");
        return -1;
    }

    memset(&srv_un, 0, sizeof(srv_un));
    srv_un.sun_family = AF_UNIX;
    strncpy(srv_un.sun_path, UNIX_DOMAIN, sizeof(srv_un.sun_path) - 1);
    rv = connect(connect_fd, (struct sockaddr *)&srv_un, sizeof(srv_un));
    if (rv < 0) {
        perror("connect: ");
        close(connect_fd);
        return -1;
    }

    return 0;
}

static int shmread(shared_use_t *shared)
{
    int rv;

    rv = semaphore_p();
    if (rv < 0) {
        return -1;
    }

    shared->pktlen = ((shared_use_t *)shm)->pktlen;
    memcpy(shared->pkt, ((shared_use_t *)shm)->pkt, shared->pktlen);

    rv = semaphore_v();
    if (rv < 0) {
        return -1;
    }

    return 0;
}

static void print_pkt(shared_use_t shared_pkt)
{
    int i;

    printf("********** RECV PACKET **********\n");
    for (i = 0; i < shared_pkt.pktlen; i++) {
        printf("0x%02x ", shared_pkt.pkt[i]);
        if ((i + 1) % 16 == 0) {
            printf("\n");
        }
    }
    printf("**********     END     **********\n");
    printf("\n");
}

int main()
{
    int rv;
    int shmid;
    char cmd[10];
    shared_use_t shared_pkt;

    rv = semaphore_init();
    if (rv < 0) {
        printf("Init a semaphore fail.\n");
    }

    shmid = sharemmy_init();
    if (shmid == -1) {
        printf("Init a share memory fail.\n");
        return 0;
    }

    usleep(10*1000);
    rv = domain_client();
    if (rv < 0) {
        printf("Create domain client socket fail.\n");
        return 0;
    }
    printf("Client init success.\n");

    while (1) {
        memset(cmd, 0, 10);
        rv = recv(connect_fd, cmd, sizeof(cmd), 0);
        if (rv < 0) {
            printf("Recv cmd from server fail.\n");
            close(connect_fd);
            break;
        }
        if (strstr(cmd, "send") != NULL || strstr(cmd, "Send") != NULL) {
            rv = shmread(&shared_pkt);
            if (rv < 0) {
                printf("Read packet from share memory fail.\n");
                break;
            }
            print_pkt(shared_pkt);
            continue;
        } else if (strstr(cmd, "quit") != NULL || strstr(cmd, "Quit") != NULL) {
            printf("Quit the packet recv client.\n");
            break;
        } else {
            printf("Unrecognized command for client.\n");
            break;
        }
    }

    rv = sharemmy_destroy(shmid, shm);
    if (rv < 0) {
        printf("Destroy share memory fail.\n");
        return 0;
    }
    close(connect_fd);

    return 1;
}

以上两个程序实现的功能:shm_test1接收用户输入命令,如果是send则将向共享内存区域写入一个报文,并发送socket消息通知进程shm_test2从共享内存中读出报文并打印出来。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值