服务端将数据发送到共享内存段:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<string.h>
#include<stdint.h>
#include<stdatomic.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<errno.h>
#include<time.h>
#include"../persistence.h"
#define SEMKEYPATH "/dev/null" /**< Path used on ftok for semget key */
#define SEMKEYID 1
#define NUMSEMS 2
#define SHMPATH "/tmp/rpc_server"
int semtimedop(int semid, struct sembuf *sops, unsigned nsops,
const struct timespec *timeout);
typedef struct image {
int seq_num;
char name[20];
size_t size;
uint8_t data[0];
}Image;
typedef struct rpc_server {
int32_t semid;
void* shm_addr;
size_t size;
struct sembuf operations[2];
}RPCServer;
RPCServer* construct_rpc_server(size_t size)
{
int32_t semid, rc;
key_t semkey;
int16_t sarray[NUMSEMS];
RPCServer* pthis = (RPCServer *)malloc(sizeof(*pthis));
if (!pthis)
return NULL;
/**
* Create an IPC key for the semaphore set.
*/
semkey = ftok(SEMKEYPATH, SEMKEYID);
if (semkey == (key_t)-1) {
perror("ftok");
goto free;
}
/**
* Create a semphore set using the IPC key. The number of
* semphores in the set is two. If a semphore set already
* exists for the key, return an error. The specified permission give everyone read/write access to the semphore set.
*/
semid = semget(semkey, NUMSEMS, 0666 | IPC_CREAT | IPC_EXCL);
if (semid == -1) {
perror("semget");
goto free;
}
pthis->semid = semid;
/**
* Initialize the first semphore and the second semaphore
* int the set to 0.
*
* The first semaphore in the sem set means:
* '1' -- The shared memory segment is being used.
* '0' -- The shared memory segment is freed.
* The second semaphore in the sem set means:
* '1' -- The shared memory segment has been changed by
* the server.
* '0' -- The shared memory segment has not been changed
* by the server.
*/
sarray[0] = 0;
sarray[1] = 0;
rc = semctl(semid, 0, SETALL, sarray);
if (rc == -1) {
perror("semctl");
goto free;
}
int fd = open(SHMPATH, O_RDWR|O_CREAT|O_TRUNC, 0644);
if (fd < 0) {
perror("open");
goto free;
}
ftruncate(fd, size);
pthis->size = size;
pthis->shm_addr = mmap(NULL, size,
PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (pthis->shm_addr == MAP_FAILED) {
perror("mmap");
close(fd);
goto free;
}
close(fd);
return pthis;
free:
free(pthis);
return NULL;
}
int rpc_send(RPCServer* pthis, void* data, size_t size)
{
int ret, rc;
static uint32_t next = 1;
struct sembuf operations[2];
const struct timespec timeout = {.tv_sec = 10UL, .tv_nsec = 0UL};
union semun {
int val;
struct semid_ds *buf;
ushort *array;
} arg;
ret = semctl(pthis->semid, 1, GETVAL, arg);
operations[0].sem_num = 1;
operations[0].sem_op = 0;
operations[0].sem_flg = 0;
operations[1].sem_num = 0;
operations[1].sem_op = 1;
operations[1].sem_flg = 0;
rc = semtimedop(pthis->semid, operations, (size_t)2, &timeout);
if (rc == -1) {
perror("semop");
return -1;
}
memcpy(pthis->shm_addr, data, size);
printf("fanout: %d\n", next++);
operations[0].sem_num = 0;
operations[0].sem_op = -1;
operations[0].sem_flg = 0;
operations[1].sem_num = 1;
operations[1].sem_op = 2;
operations[1].sem_flg = 0;
rc = semop(pthis->semid, operations, 2);
if (rc == -1) {
perror("semop");
return -1;
}
return 0;
}
void destroy_ipc_server(RPCServer **ppthis)
{
int32_t ret, rc;
if (!ppthis) return;
if (!*ppthis) return;
ret = semctl((*ppthis)->semid, 1, IPC_RMID);
if (rc == -1) {
perror("semctl");
}
ret = munmap((*ppthis)->shm_addr, (*ppthis)->size);
if (ret < 0) {
perror("munmap");
}
free(*ppthis);
*ppthis = NULL;
return;
}
int main()
{
size_t size;
uint8_t* data;
read_jpg_file("./test.jpg", &data, &size);
size = size + sizeof(Image);
RPCServer* pthis = construct_rpc_server(size);
Image* img = (Image*)malloc(size);
memset(img, 0, sizeof(*img));
memcpy(img->data, data, size);
img->size = size;
strcpy(img->name, "xxdk");
int total = 100;
while(total--) {
usleep(1000*20);
img->seq_num++;
rpc_send(pthis, img, size);
}
sleep(1);
destroy_ipc_server(&pthis);
return 0;
}
客户端读取服务端的数据跟新:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<stdint.h>
#include<string.h>
#include<stdatomic.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<errno.h>
#include"../persistence.h"
#define SEMKEYPATH "/dev/null"
#define SEMKEYID 1
#define NUMSEMS 2
#define SHMPATH "/tmp/rpc_server"
typedef struct image {
int seq_num;
char name[20];
size_t size;
uint8_t data[0];
}Image;
typedef struct rpc_client {
int32_t semid;
void* shm_addr;
size_t size;
struct sembuf operations[2];
}RPCClient;
RPCClient* construct_rpc_client(size_t size)
{
key_t semkey;
int32_t semid, rc;
RPCClient* pthis = (RPCClient*)malloc(sizeof(*pthis));
if (!pthis)
return NULL;
semkey = ftok(SEMKEYPATH, SEMKEYID);
if (semkey == (key_t)-1) {
perror("ftok");
goto free;
}
pthis->semid = semget(semkey, NUMSEMS, 0666);
if (pthis->semid == -1) {
perror("semget");
goto free;
}
int fd = open(SHMPATH, O_RDWR, 0644);
if (fd < 0) {
perror("open");
goto free;
}
ftruncate(fd, size);
pthis->size = size;
pthis->shm_addr = mmap(NULL, size,
PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (pthis->shm_addr == MAP_FAILED) {
perror("mmap");
close(fd);
goto free;
}
close(fd);
return pthis;
free:
free(pthis);
return NULL;
}
int rpc_recv(RPCClient* pthis)
{
int rc;
char name[32] = {0};
struct sembuf operations[2];
operations[0].sem_num = 1;
operations[0].sem_op = -1;
operations[0].sem_flg = 0;
operations[1].sem_num = 0;
operations[1].sem_op = 1;
operations[1].sem_flg = IPC_NOWAIT|SEM_UNDO;
rc = semop(pthis->semid, operations, 1);
if (rc == -1) {
perror("semop");
return -1;
}
Image* p = (Image *)pthis->shm_addr;
printf("seq_num = %d, name = %s, size = %ld\n",
p->seq_num, p->name, p->size);
sprintf(name, "./image/%d.jpg", p->seq_num);
//write_jpg_file(name, p->data, p->size);
operations[0].sem_num = 0;
operations[0].sem_op = -1;
operations[0].sem_flg = IPC_NOWAIT;
operations[0].sem_num = 1;
operations[0].sem_op = -1;
operations[0].sem_flg = 0;
rc = semop(pthis->semid, operations, 2);
if (rc == -1) {
perror("semop");
return -1;
}
return 0;
}
void destroy_ipc_client(RPCClient** ppthis)
{
if (!ppthis) return;
if (!*ppthis) return;
int ret = munmap((*ppthis)->shm_addr, (*ppthis)->size);
if (ret < 0) {
perror("munmap");
exit(4);
}
free(*ppthis);
*ppthis = NULL;
return;
}
int main()
{
RPCClient* pthis = construct_rpc_client(5*1024*1024);
while (1) {
if (rpc_recv(pthis) < 0)
break;
}
destroy_ipc_client(&pthis);
return 0;
}