首页 > 技术文章 > Linux下C语言进程通讯编程

uestc-mm 2017-10-05 22:18 原文

一、基础代码API使用例程:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <sys/shm.h>
 4 /*************基本的函数API********************
 5 共享内存函数API
 6 int shmget(key_t key, int size, int flag)
 7 key:
 8     共享内存的键值,多个进程可以通过它访问同一个共享内存。常用特殊值:IPC_PRIVATE,创建当前进程的私有共享内存
 9 size:
10     指定创建共享内存的大小
11 flag:
12     操作权限
13 char * shmat(int shm_id, const void * addr, int flag)
14 shm_id:
15     要映射的共享内存标识符
16 addr:
17     指定在调用进程中映射共享内存的地址。通常取值为0,表示由系统自动分配地址。
18 flag:
19     设置共享内存的操作权限。若取值为0,表示可对共享内存进行读写操作。
20 int shmctl(int shm_id, int cmd, struct shmid_ds * buf)
21 shm_id:
22     共享内存标识符
23 cmd:
24     指定索要进行的操作:IPC_STAT IPC_SET IPC_RMID SHM_LOCK SHM_UNLOCK
25 buf:
26     结构体型指针
27 int shmdt(const void * addr)
28 **********************************************/
29 #define Test_pipe 0
30 #define Test_Shmget 0
31 #define Test_AT_w 0
32 #define Test_AT_r 0
33 #define Test_DT 1
34 int main(int argc, char *argv[])
35 {
36 #if Test_pipe
37     int x,fd[2];
38     char buf[30],s[30];
39     pipe(fd);
40     x = fork();
41     if(0 == x)
42     {
43         sprintf(buf,"This is an pipe!");
44         write(fd[1],buf,30);
45         exit(0);
46     }
47     else
48     {
49         wait(0);
50         read(fd[0],s,30);
51         printf("read: %s\n",s);
52     }
53 #endif
54 
55 #if Test_Shmget
56     int shm_id;
57     shm_id = shmget(IPC_PRIVATE,4096,0666);
58     if(shm_id < 0)
59     {
60         perror("shmget id < 0");
61         exit(0);
62     }
63     printf("成功建立共享内存区域: %d\n",shm_id);
64     system("ipcs -m");
65 #endif
66 
67 #if Test_AT_w
68     int shm_id;
69     char *shm_buf;
70     shm_id = atoi(argv[1]);
71     shm_buf = shmat(shm_id,0,0);
72     printf("写如数据到共享内存:\n");
73     sprintf(shm_buf,"对共享内存的读写操作!");
74     printf("%s\n",shm_buf);
75 #endif
76 
77 #if Test_AT_r
78         int shm_id;
79         char *shm_buf,str;
80         shm_id = atoi(argv[1]);
81         shm_buf = shmat(shm_id,0,0);
82         printf("写如数据到共享内存:\n");
83         sprintf(str,shm_buf);
84         printf("%s\n",str);
85     system("ipcs -m");
86 #endif
87 
88 #if Test_DT
89         int shm_id;
90         char *shm_buf;
91         shm_id = atoi(argv[1]);
92         shm_buf = shmat(shm_id,0,0);
93     shmdt(shm_buf);
94     shmctl(shm_id,IPC_RMID,NULL);
95     system("ipcs -m");
96 #endif
97 }

二、接口详细介绍

三、基础实例

1)IPC通讯中共享内存参看代码:

Client端代码client.cgcc client.c -lm -o client) 

shmget函数得到的共享内存的大小有参数确定,参数的单位是Byte!

同样的shmget参数的0666代表的内容是,共享内存空间的可读可写性!

使用ftok函数获取的key_t key的作用在于生成一个文件节点引索,这样才能够连接两个进程让他们以这个引索值作为标识ID!

shmdt函数用来删除释放掉创建的共享内存空间!

shmat函数用来映射已经创建好的虚拟内存空间地址!返回值为两个进程进行操作的共享内存起始地址!

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <time.h>
#include <math.h>

#define random(x) (rand()%x)
#define PI 3.1415926

#define Width 20
#define Height 20

int main(int argc,char *argv[])
{
        key_t key = 0;
        int shmid = 0;
        setbuf(stdout,NULL);
        printf("Begin to Create the shared-mem...\n");
        key = ftok(".",2); // Get the only IPC ID:inode'num + 1
        if(key<0)
        {       
                perror("ftok");
                return -1;
        }
        printf("key=%d\n",key);
        sleep(1);
        printf("...\n");
        printf("%d\n",IPC_CREAT);
        shmid = shmget(key,100,IPC_EXCL | IPC_CREAT | 0666); // Get shared mem:IPC_ID_key Mem_size
        if(shmid<0)
        {
                perror("shmget");
                return -2;
        }
        char * shared_mem_addr = shmat(shmid,NULL,0); // mapping the mem_addr to the addr of the Process
        printf("...\n");

        sleep(2); // waitting for setup the mem

        printf("The shared-mem create sucessfully!\n");
        printf("Begin to insert the data into shared-mem!\n");
        int i=0;
        while(i<Width*Height)
        {
                *(shared_mem_addr+i) = 200*sin((double)i*PI/180.0);// random(255)+255;
                usleep(100);
                printf(".");
                i++;
        }
        printf("\nThe data insert finish!\n");
        shmdt(shared_mem_addr);
        return 0;
}

Server端代码server.cgcc server.c -o server

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <time.h>

#define Width 20
#define Height 20

int main(int argc,char *argv[])
{
        key_t key = 0;
        int shmid = 0;
        key = ftok(".",2); // Get the only IPC ID:inode'num + 1
        if(key<0)
        {
                perror("ftok");
                return -1;
        }
        shmid = shmget(key,100,IPC_CREAT | 0666); // Get shared mem:IPC_ID_key Mem_size
        if(shmid<0)
        {
                perror("shmget");
                return -2;
        }
        char * shared_mem_addr = shmat(shmid,NULL,0); // mapping the mem_addr to the addr of the Process

        sleep(2);

        int i=0;
        while(i<Width*Height)
        {
                printf("The image data:%d\n",*(shared_mem_addr+i));
                usleep(100);
                i++;
        }
        shmdt(shared_mem_addr);
        sleep(1);
        shmctl(shmid,IPC_RMID,NULL);
        return 0;
}

首先运行Clent端,然后再运行Server端即可!

2)Python与C语言共享内存实例

python内存共享:

from ctypes import *  
import numpy as np
import codecs
import datetime

SHM_SIZE = 1024*1024*20 # 20MBytes
SHM_KEY = 123559  

OUTFILE="Shared.PNG"  
try:  
    rt = CDLL('librt.so')  
except:  
    rt = CDLL('librt.so.1')

shmget = rt.shmget
shmget.argtypes = [c_int, c_size_t, c_int]  
shmget.restype = c_int  
shmat = rt.shmat  
shmat.argtypes = [c_int, POINTER(c_void_p), c_int]  
shmat.restype = c_void_p  

shmid = shmget(SHM_KEY, SHM_SIZE, 0o666)

if shmid < 0:  
    print ("System not infected")  
else:
    addr = shmat(shmid, None, 0)  
    f=open(OUTFILE, 'wb')
    begin_time = datetime.datetime.now()
    DataLength = int.from_bytes(string_at(addr,4), byteorder='little', signed=True)   #这里数据文件是小端int16类型
    ImgData = string_at(addr+4,DataLength)
    end_time = datetime.datetime.now()
    print(DataLength, ' Bytes')
    print('Type:',type(ImgData),' Bytes:', len(ImgData))
    f.write(ImgData)
    f.close()  
#print ("Dumped %d bytes in %s" % (SHM_SIZE, OUTFILE))
print("Success!",end_time-begin_time)

C Transform:

#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>

#define SHAERD_MEM_SIZE 20 * 1024 * 1024 // 20MBytes

char mem_free(void *ptr);
time_t get_timestamp_ms(void);
char *file_read(unsigned int *file_bytes, char *file_name);

int main(int argc, char *argv[])
{
    int id = 0;
    size_t offset = 0;
    char *data = NULL;
    char *ImgData = NULL;
    unsigned int file_bytes = 0;
    time_t start_time, end_time;   
    if (argc < 2)
    {
        printf("args too less\n");
        return 0;
    }
    
    id = shmget(123559, SHAERD_MEM_SIZE, IPC_CREAT | 0777);
    if (id < 0)
    {
        printf("get id failed\n");
        return 0;
    }
    
    data = shmat(id, NULL, 0);
    if (data == NULL)
    {
        printf("shamt failed\n");
        return 0;
    }

    ImgData = file_read(&file_bytes, argv[1]);
    offset = sizeof(unsigned int);
    printf("Size of unsigned long:%d\n", offset);
    printf("Size of Image File:%d\n", file_bytes);
    start_time = get_timestamp_ms();
    memcpy(data, &file_bytes, sizeof(unsigned int));
    memcpy(data + offset, ImgData, file_bytes);
    end_time = get_timestamp_ms();

    printf("Time Cost:%d\n", end_time - start_time);

    mem_free(ImgData);

    return 0;
}

char *file_read(unsigned int *file_bytes, char *file_name)
{
  int file_size;
  FILE *fd = NULL;
  char *file_data = NULL;
  fd = fopen(file_name, "rw");
  if(fd < 0)
  {
    printf("File open failed...\n");
    return NULL;
  }
  fseek(fd, 0, SEEK_END);
  file_size = ftell (fd);
  file_data = malloc(sizeof(char)*file_size);
  if(file_data == NULL)
  {
    printf("Malloc failed...\n");
    return NULL;
  }
  fseek(fd, 0, SEEK_SET);
  *file_bytes = fread(file_data,sizeof(char),file_size,fd);
  fclose(fd);
  return file_data;
}

time_t get_timestamp_ms(void)
{
  time_t timestamp_ms = 0;
  struct timeval tv;
  
  gettimeofday(&tv,NULL);
  timestamp_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
  return timestamp_ms;
}

char mem_free(void *ptr)
{
  if(NULL != ptr)
  {
    free(ptr);
    return 0;
  }
  printf("Memory is Empty...\n");
  return -1;
}

python-c指针传递

import os
import sys
import time
import ctypes
from ctypes import *
from ctypes import cdll

BUFF_SIZE = 6*1024*1024

class POINT(Structure): # 定义了一个类,类当中的基本成员变量包括了x、y, 相当于C语言中的 struct POINT{int x;inty};
    _fields_ = [("x", c_int),("y", c_int),("addr", POINTER(c_uint8))]

DataPoint = (c_uint8 * 10)() # 定义一个大小为10指针实例作为缓存
DataPoint[3] = 22

point = POINT(10, 20, DataPoint) # 定义个类对象Obj, 相当于 struct POINT point={10,20};
print('Line', sys._getframe().f_lineno, ':', point.x, point.y, point.addr[3])

point = POINT(y=5) # 定义个类对象Obj, 相当于 struct POINT point={,20};
print('Line', sys._getframe().f_lineno, ':', point.x, point.y)


TenPointsArrayType = POINT * 3 # 重定义了一个POINT数组类型,相当于C语言中的 #define TenPointsArrayType POINT*3
arr = TenPointsArrayType()
for pt in arr:
    print(pt.x, pt.y, pt.addr)

p = os.getcwd() + '/libfunc.so' # 获取当前的动态库的绝对路径位置
f = cdll.LoadLibrary(p) # 使用LoadLibrary接口加载C语言动态库
function = f.py_point_address # 从当前库当中取得clib中的函数py_point_address,并重命名为function
function.argtypes = [POINTER(c_byte)] # 设置当前函数的输入参数

i = ctypes.c_int(42) # 定义一个整数类型的变量,变量初始值为 42,相当于C语言中的 int i=42;
pi = ctypes.pointer(i) # 通过使用pointer接口获取,相当于C语言中的 int *pi = &i;
print('Line', sys._getframe().f_lineno, ':', pi.contents) # 查看指针变量的信息
print('Line', sys._getframe().f_lineno, ':', pi[0]) # 查看指针所指向的内容,相当于C语言中的 *pi;

a = (c_byte * BUFF_SIZE)() # 定义一个大小为BUFF_SIZE指针实例作为缓存
# cast(a, POINTER(c_uint8)) # 函数可以将一个指针实例强制转换为另一种 ctypes 类型
print('Line', sys._getframe().f_lineno, ':', a)
print('Line', sys._getframe().f_lineno, ':', type(a))
time_start = time.time()
function(a) # 执行function函数并传入a地址参数
time_end = time.time()

for i in range(10):
    print(a[i])

print('Line', sys._getframe().f_lineno, ':', 'TimeCost:', (time_end - time_start)*1000, 'ms') # 记录当前函数调用消耗的时间

data = ctypes.c_uint8(10) # 定义一个整数类型的变量,变量初始值为 10,相当于C语言中的 char data=42;
data_addr = ctypes.byref(data, 0) # 通过使用byref接口获取地址,相当于C语言中的 char *data_addr = &data; byref(obj, offset) 对应于这段 C 代码:(((char *)&obj) + offset)
print('Line', sys._getframe().f_lineno, ':', type(data))
print('Line', sys._getframe().f_lineno, ':', type(data_addr))

value = 'hello world'  # 定义一个字符串变量
address = id(value)  # 获取value的地址,赋给address
get_value = ctypes.cast(address, ctypes.py_object).value  # 读取地址中的变量
print('Line', sys._getframe().f_lineno, ':', address, get_value) # 

res = f.func(99) # 普通函数调用
print('Line', sys._getframe().f_lineno, ':', res)

C:

#include <stdio.h>
#include <sys/shm.h>
#include <string.h>
#include <stdlib.h>

#define BUFF_SIZE 6*1024*1024

/* func.c */
int func(int a)
{
        return a*a;
}

void cycle_calc(int b)
{
    int count = 100;
    while(count--){
        b*=2;
        printf("%d - %d\n", count, b);
    }
}

unsigned char * c_point_address(void)
{
    unsigned char *Img = malloc(sizeof(unsigned char)*1000);
    printf("C-Address:%d\n", Img);
    memset(Img, 20, 1000);
    return Img;
}

int py_point_address(unsigned char * Addr)
{
    unsigned char *Img = malloc(sizeof(unsigned char)*BUFF_SIZE);
    // printf("C-Address:%x\n", Img);
    // printf("Python-Address:%x\n", Addr);
    memset(Img, 20, BUFF_SIZE);
    memcpy((unsigned char * )Addr, Img, BUFF_SIZE);
    return 1;
}

shell compile:

#!/bin/bash
gcc -fPIC -shared function.c -o libfunc.so
python3 MemoryTest.py

 

https://www.cnblogs.com/mq0036/p/8492621.html

https://www.cnblogs.com/dzzy/p/9376588.html

参看IPC通讯介绍:https://www.cnblogs.com/CheeseZH/p/5264465.html

推荐阅读