博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
mm_camera_sock
阅读量:6815 次
发布时间:2019-06-26

本文共 13080 字,大约阅读时间需要 43 分钟。

  QCamera 中 是需要进程间通讯的。因为 Camera Sensor 和 ISP Driver 在另一个Demon进程中,CameraHAL进程是需要和Demon进程通讯,那么使用的通讯方式是 UNIX Domain Socket IPC.

  Domain Socket : 

  一个Domain Socket示例:

/* server.c */#include 
#include
#include
#include
#include
#include
#include
#include
#include
// the max connection number of the server#define MAX_CONNECTION_NUMBER 5typedef enum { UNIX_SOCK_TYPE_UDP, UNIX_SOCK_TYPE_TCP,} unix_sock_type_t;int unix_socket_create(const char *servername, unix_sock_type_t sock_type){ int socket_fd; struct sockaddr_un addr_un; int sktype; int rc; switch (sock_type) { case UNIX_SOCK_TYPE_UDP: sktype = SOCK_DGRAM; break; case UNIX_SOCK_TYPE_TCP: sktype = SOCK_STREAM; break; default: printf("[ %s, %d ] unknow socket type = %d\n", __func__, __LINE__, sock_type); return -1; } socket_fd = socket(AF_UNIX, sktype, 0); if (socket_fd < 0) { printf("[ %s, %d ] create socket fd = %d failed.\n", __func__, __LINE__, socket_fd); return socket_fd; } memset(&addr_un, 0, sizeof(addr_un)); addr_un.sun_family = AF_UNIX; strncpy(addr_un.sun_path, servername, sizeof(addr_un.sun_path)-1); unlink(servername); // in case it already exists. printf("addr_un.sun_path: %s\n", addr_un.sun_path); rc = bind(socket_fd, (struct sockaddr *) &addr_un, sizeof(addr_un)); if (rc < 0) { close(socket_fd); socket_fd = -1; printf("[ %s, %d ] bind error : %s ", __func__, __LINE__, strerror(errno)); } return socket_fd;}void unix_socket_close(int fd){ if (fd >= 0) { close(fd); }}int unix_socket_listen(int fd){ return listen(fd, MAX_CONNECTION_NUMBER);}int main(void){ int socket_fd = 0; int accept_socket_fd = 0; int rc = 0; char read_buf[256]; ssize_t read_length; // 1. create domain socket and bind socket_fd = unix_socket_create("test.socket", UNIX_SOCK_TYPE_TCP); if (socket_fd < 0) { printf("create domain socket error.\n"); exit(0); } // 2. listen rc = unix_socket_listen(socket_fd); if (rc < 0) { printf("listen domain socket error.\n"); goto err; } // 3. accept and read while (1) { accept_socket_fd = accept(socket_fd, NULL, NULL); if (accept_socket_fd < 0) { printf("accept error.\n"); usleep(1000 * 50); continue; } while ((read_length = read(accept_socket_fd, read_buf, sizeof(read_buf))) > 0) { printf("read %ld bytes: %s\n", read_length, read_buf); } if (read_length == -1) { printf("read error.\n"); exit(-1); } else if (read_length == 0) { printf("END...\n"); break; } } err: unix_socket_close(socket_fd); return 0;}
/* client.c */#include 
#include
#include
#include
#include
#include
#include
#include
#include
typedef enum { UNIX_SOCK_TYPE_UDP, UNIX_SOCK_TYPE_TCP,} unix_sock_type_t;int unix_socket_create(const char *servername, unix_sock_type_t sock_type){ int socket_fd; struct sockaddr_un addr_un; int sktype; int rc; switch (sock_type) { case UNIX_SOCK_TYPE_UDP: sktype = SOCK_DGRAM; break; case UNIX_SOCK_TYPE_TCP: sktype = SOCK_STREAM; break; default: printf("[ %s, %d ] unknow socket type = %d\n", __func__, __LINE__, sock_type); return -1; } socket_fd = socket(AF_UNIX, sktype, 0); if (socket_fd < 0) { printf("[ %s, %d ] create socket fd = %d failed.\n", __func__, __LINE__, socket_fd); return socket_fd; } memset(&addr_un, 0, sizeof(addr_un)); addr_un.sun_family = AF_UNIX; strncpy(addr_un.sun_path, servername, sizeof(addr_un.sun_path)-1); rc = connect(socket_fd, (struct sockaddr *)&addr_un, sizeof(addr_un)); if (0 != rc) { close(socket_fd); socket_fd = -1; printf("[ %s, %d ] bind error : %s ", __func__, __LINE__, strerror(errno)); } return socket_fd;}void unix_socket_close(int fd){ close(fd);}int main(void){ int socket_fd = 0; int rc = 0; char buf[256]; // 1. create domain socket and bind socket_fd = unix_socket_create("test.socket", UNIX_SOCK_TYPE_TCP); if (socket_fd < 0) { printf("create domain socket error.\n"); exit(0); } while (scanf("%s", buf) != EOF) { if (write(socket_fd, buf, sizeof(buf)) < 0) { printf("write error\n"); exit(-1); } } return 0;}

 

 

  下边看 mm_camera_sock 相关方法,该部分为 UNIX Domain Socket 的 Client端。

/* 重要结构体和用户API */typedef enum {    MM_CAMERA_SOCK_TYPE_UDP,    MM_CAMERA_SOCK_TYPE_TCP,} mm_camera_sock_type_t;typedef union {    struct sockaddr addr;    struct sockaddr_un addr_un;} mm_camera_sock_addr_t;int mm_camera_socket_create(int cam_id, mm_camera_sock_type_t sock_type);   // 创建 socket 并且建立连接int mm_camera_socket_sendmsg(  int fd,  void *msg,  size_t buf_size,  int sendfd);int mm_camera_socket_bundle_sendmsg(          // 发送消息  int fd,  void *msg,  size_t buf_size,  int sendfds[CAM_MAX_NUM_BUFS_PER_STREAM],  int num_fds);int mm_camera_socket_recvmsg(                // 接收消息  int fd,  void *msg,  uint32_t buf_size,  int *rcvdfd);void mm_camera_socket_close(int fd);        // 关闭 socket 连接

 

int mm_camera_socket_create(int cam_id, mm_camera_sock_type_t sock_type){    int socket_fd;    mm_camera_sock_addr_t sock_addr;    int sktype;    int rc;    switch (sock_type)    {      case MM_CAMERA_SOCK_TYPE_UDP:        sktype = SOCK_DGRAM;        break;      case MM_CAMERA_SOCK_TYPE_TCP:        sktype = SOCK_STREAM;        break;      default:        CDBG_ERROR("%s: unknown socket type =%d", __func__, sock_type);        return -1;    }    socket_fd = socket(AF_UNIX, sktype, 0); // 创建 socket     if (socket_fd < 0) {        CDBG_ERROR("%s: error create socket fd =%d", __func__, socket_fd);        return socket_fd;    }    memset(&sock_addr, 0, sizeof(sock_addr));    sock_addr.addr_un.sun_family = AF_UNIX;    snprintf(sock_addr.addr_un.sun_path,             UNIX_PATH_MAX, QCAMERA_DUMP_FRM_LOCATION"cam_socket%d", cam_id);    rc = connect(socket_fd, &sock_addr.addr, sizeof(sock_addr.addr_un));     // 建立连接    if (0 != rc) {      close(socket_fd);      socket_fd = -1;      CDBG_ERROR("%s: socket_fd=%d %s ", __func__, socket_fd, strerror(errno));    }    CDBG("%s: socket_fd=%d %s", __func__, socket_fd,        sock_addr.addr_un.sun_path);    return socket_fd;}void mm_camera_socket_close(int fd){    if (fd >= 0) {      close(fd);   // 关闭 socket    }}

 

  在了解 mm_camera_socket_sendmsg ,mm_camera_socket_bundle_sendmsg, mm_camera_socket_recvmsg 之前,要说明2个重要的函数: sendmsg 和 recvmsg

ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

 

  在这两个函数中,对于数据的封装使用结构体 struct msghdr ,所以有必要看下 struct msghdr 的定义及意义。

struct iovec {                    /* Scatter/gather array items */               void  *iov_base;              /* Starting address */               size_t iov_len;               /* Number of bytes to transfer */           };           struct msghdr {               void         *msg_name;       /* optional address */               socklen_t     msg_namelen;    /* size of address */               struct iovec *msg_iov;        /* scatter/gather array */               size_t        msg_iovlen;     /* # elements in msg_iov */               void         *msg_control;    /* ancillary data, see below */               size_t        msg_controllen; /* ancillary data buffer len */               int           msg_flags;      /* flags on received message */           }; 1. msg_name : 在 unconnected socket 中用于为 datagram (数据报文) 指定 target address. 在 connected socket 中,该字段没有意义,应该置NULL,msg_nameleng 为0 2. msg_control : 用于封装 control-related messages or miscellaneous ancillary data. (杂项辅助资料)

 

  control message 封装:

struct cmsghdr {               socklen_t     cmsg_len;     /* data byte count, including hdr */               int           cmsg_level;   /* originating protocol */               int           cmsg_type;    /* protocol-specific type */           /* followed by               unsigned char cmsg_data[]; */           };    cmghdr 访问接口:       CMSG_FIRSTHDR() returns a pointer to the first cmsghdr in the ancillary data buffer associated with the passed msghdr.       CMSG_NXTHDR() returns the next valid cmsghdr after the passed cmsghdr.  It returns NULL when there isn't enough space left in the buffer.       CMSG_ALIGN(), given a length, returns it including the required alignment.  This is a constant expression.       CMSG_SPACE() returns the number of bytes an ancillary element with payload of the passed data length occupies.  This is a constant expression.       CMSG_DATA() returns a pointer to the data portion of a cmsghdr.       CMSG_LEN() returns the value to store in the cmsg_len member of the cmsghdr structure, taking into account any necessary alignment.  It takes the data length as an  argument.   This  is  a  constant       expression.

 

  对于上述接口,细节部分可以参考 man 手册.int mm_camera_socket_sendmsg(

int fd,           // socket fd  void *msg,        // msg  size_t buf_size,  // msg size  int sendfd)       // 需要发送的 fd,即该 fd 作为消息的一部分需要发送。发送 fd 和发送普通消息的方式当然是不一样的。{    struct msghdr msgh;    struct iovec iov[1];    struct cmsghdr * cmsghp = NULL;      // ancillary data(辅助控制杂项消息) 的封装结构体    char control[CMSG_SPACE(sizeof(int))];  // control 用来存放 sendfd ,即控制消息     if (msg == NULL) {      CDBG("%s: msg is NULL", __func__);      return -1;    }    memset(&msgh, 0, sizeof(msgh));    msgh.msg_name = NULL;    msgh.msg_namelen = 0;    iov[0].iov_base = msg;    iov[0].iov_len = buf_size;    msgh.msg_iov = iov;    msgh.msg_iovlen = 1;         // 将普通消息封装好    CDBG("%s: iov_len=%llu", __func__,            (unsigned long long int)iov[0].iov_len);    msgh.msg_control = NULL;    msgh.msg_controllen = 0;    /* if sendfd is valid, we need to pass it through control msg */    if( sendfd >= 0) {    // 如何 sendfd 有效,需要通过 socket 发送,但是是通过 control msg ,而不是普通消息      msgh.msg_control = control;      msgh.msg_controllen = sizeof(control);      cmsghp = CMSG_FIRSTHDR(&msgh);           // CMSG_FIRSTHDR 返回指向 ancillary data buffer 的第一个 cmsghdr 的指针。注意传入的参数      if (cmsghp != NULL) {        CDBG("%s: Got ctrl msg pointer", __func__);        cmsghp->cmsg_level = SOL_SOCKET;        cmsghp->cmsg_type = SCM_RIGHTS;        cmsghp->cmsg_len = CMSG_LEN(sizeof(int));        *((int *)CMSG_DATA(cmsghp)) = sendfd;      // CMSG_DATA 返回 cmsghdr 的数据域指针。        CDBG("%s: cmsg data=%d", __func__, *((int *) CMSG_DATA(cmsghp)));      } else {        CDBG("%s: ctrl msg NULL", __func__);        return -1;      }    }    return sendmsg(fd, &(msgh), 0);  // 发送消息} // 和上一个函数的区别就是要发送多个 sendfds。 int mm_camera_socket_bundle_sendmsg(  int fd,  void *msg,  size_t buf_size,  int sendfds[CAM_MAX_NUM_BUFS_PER_STREAM],  int numfds){    struct msghdr msgh;    struct iovec iov[1];    struct cmsghdr * cmsghp = NULL;    char control[CMSG_SPACE(sizeof(int) * numfds)];    int *fds_ptr = NULL;    if (msg == NULL) {      CDBG("%s: msg is NULL", __func__);      return -1;    }    memset(&msgh, 0, sizeof(msgh));    msgh.msg_name = NULL;    msgh.msg_namelen = 0;    iov[0].iov_base = msg;    iov[0].iov_len = buf_size;    msgh.msg_iov = iov;    msgh.msg_iovlen = 1;    CDBG("%s: iov_len=%llu", __func__,            (unsigned long long int)iov[0].iov_len);    msgh.msg_control = NULL;    msgh.msg_controllen = 0;    /* if numfds is valid, we need to pass it through control msg */    if (numfds > 0) {      msgh.msg_control = control;      msgh.msg_controllen = sizeof(control);      cmsghp = CMSG_FIRSTHDR(&msgh);      if (cmsghp != NULL) {        cmsghp->cmsg_level = SOL_SOCKET;        cmsghp->cmsg_type = SCM_RIGHTS;        cmsghp->cmsg_len = CMSG_LEN(sizeof(int) * numfds);        fds_ptr = (int*) CMSG_DATA(cmsghp);        memcpy(fds_ptr, sendfds, sizeof(int) * numfds);      } else {        CDBG_ERROR("%s: ctrl msg NULL", __func__);        return -1;      }    }    return sendmsg(fd, &(msgh), 0);} // 和 sendmsg 类似,不再分析 int mm_camera_socket_recvmsg(  int fd,  void *msg,  uint32_t buf_size,  int *rcvdfd){    struct msghdr msgh;    struct iovec iov[1];    struct cmsghdr *cmsghp = NULL;    char control[CMSG_SPACE(sizeof(int))];    int rcvd_fd = -1;    int rcvd_len = 0;    if ( (msg == NULL) || (buf_size <= 0) ) {      CDBG_ERROR(" %s: msg buf is NULL", __func__);      return -1;    }    memset(&msgh, 0, sizeof(msgh));    msgh.msg_name = NULL;    msgh.msg_namelen = 0;    msgh.msg_control = control;    msgh.msg_controllen = sizeof(control);    iov[0].iov_base = msg;    iov[0].iov_len = buf_size;    msgh.msg_iov = iov;    msgh.msg_iovlen = 1;    if ( (rcvd_len = recvmsg(fd, &(msgh), 0)) <= 0) {      CDBG_ERROR(" %s: recvmsg failed", __func__);      return rcvd_len;    }    CDBG("%s:  msg_ctrl %p len %zd", __func__, msgh.msg_control,        msgh.msg_controllen);    if( ((cmsghp = CMSG_FIRSTHDR(&msgh)) != NULL) &&        (cmsghp->cmsg_len == CMSG_LEN(sizeof(int))) ) {      if (cmsghp->cmsg_level == SOL_SOCKET &&        cmsghp->cmsg_type == SCM_RIGHTS) {        CDBG("%s:  CtrlMsg is valid", __func__);        rcvd_fd = *((int *) CMSG_DATA(cmsghp));        CDBG("%s:  Receieved fd=%d", __func__, rcvd_fd);      } else {        CDBG_ERROR("%s:  Unexpected Control Msg. Line=%d", __func__, __LINE__);      }    }    if (rcvdfd) {      *rcvdfd = rcvd_fd;    }    return rcvd_len;}

 

转载于:https://www.cnblogs.com/ronny-blog/p/8320388.html

你可能感兴趣的文章
mysql 创建日期列之timestamp
查看>>
VMM系列之使用VMM服务器构建 Hyper-V主机(4)
查看>>
详测 Generics Collections TList (7): Items、Contains
查看>>
配置FTP服务器(2) 本地用户下载和上传
查看>>
多线程编程(11) - 多线程同步之 Mutex (互斥对象)[续]
查看>>
【Java每日一题】20161214
查看>>
requireJs 模块化简陋版本
查看>>
我的友情链接
查看>>
How to upgrade vim to version 8 on CentOS 7
查看>>
xcode pod 报import 找不到 pods的支持问题解决方法之一
查看>>
nginx配置让任何文件在浏览器中显示文本text/plain
查看>>
思科路由器×××配置-- 动态 site-to-site ×××(上)
查看>>
Visual Studio统计有效代码行数
查看>>
Qt连接Oracle数据库常见问题
查看>>
45个实用的JavaScript技巧、窍门和最佳实践
查看>>
sqlserver 2005 列字符串拼接
查看>>
用面向接口编程思想看找对象
查看>>
TWaver GIS在电信中的使用
查看>>
MySQL5.7使用Notifier启动、停止服务时出现的问题
查看>>
今天用java弄个json数据交换接口,个人感觉这样实现省事实力。
查看>>