這次有兩個主題:

1. unix domain socket IPC

2. 傳structure

先看流程圖

domain_sock_flow 

使用unix domain socket,client跟server都要bind在某一個socket file (Note: 一個socket file只能被bind一次)。server bind完之後在recvfrom等待訊息。client bind完後connect到server的socket file,然後就開始送訊息。此時client已經connect,所以只要用send, 而不需用sendto。

server從recvfrom收到訊息,會帶有client的address (如/tmp/client.sock)。有了這個address,client就可以把訊息回傳。

而傳送struct的部分,是透過pointer。在訊息內宣告一個pointer,將整個 struct用memcpy複製到其所指的位置後送出。client收到後,再將這個pointer轉型為原來的struct即可。範例程式如下:

server.c:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/syslog.h>
#include <sys/un.h>
#include "ipc.h"

int main(int argc, char** argv)
{
    int serfd;
    struct sockaddr_un addr;
    int ret;
    struct ipc_msg *msg; /* IPC msg structure  */
    char msgbuf[MAX_BUF_LEN];
    struct test_send_struct st_msg;
    struct sockaddr_un from; /* recvfrom will fill client add */
    socklen_t fromlen = sizeof(from);

    msg = (struct ipc_msg *) msgbuf;
    serfd = socket(PF_UNIX, SOCK_DGRAM, 0);
    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path, SERVER_SOCK_FILE);

    unlink(SERVER_SOCK_FILE);
    if (bind(serfd, (struct sockaddr *)&addr,
             sizeof(addr)) == -1) { /* server bind sock file  */
        perror("bind");
        goto fail;
    }


    ret = recvfrom(serfd, msg, MAX_BUF_LEN, 0,
                   (struct sockaddr *) &from, &fromlen);

    //printf("from %s\n", from.sun_path);

    switch (msg->type) {
    case 0:
        strcpy(st_msg.msg, "send hello");
        msg->len = sizeof(st_msg);
        memcpy(msg->data, &st_msg, msg->len);
        ret = sendto(serfd, msg, MAX_BUF_LEN, 0,
                     (struct sockaddr *) &from, fromlen);
        if (ret < 0) {
            perror("sendto(interfaces)");
            return;
        }
        break;
    default:
        printf("unknown msg type\n");
        break;
    }

    return 0;

fail:
    close(serfd);
    return 1;

}


 

client.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/syslog.h>
#include <sys/un.h>
#include "ipc.h"


int main(int argc, char** argv) {
    int client_fd, len;
    int i;
    struct sockaddr_un addr;
    struct ipc_msg *msg;
    char msgbuf[MAX_BUF_LEN];
    struct test_send_struct *st_msg;

    msg = (struct ipc_msg *) msgbuf;

    if ((client_fd = socket(PF_UNIX, SOCK_DGRAM, 0)) == -1) {
        perror("socket");
        goto fail;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path, CLIENT_SOCK_FILE);
    unlink(CLIENT_SOCK_FILE);
    if (bind(client_fd, (struct sockaddr *)&addr,
             sizeof(addr)) == -1) { /* client bind sock file  */
        perror("bind");
        goto fail;
    }


    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path, SERVER_SOCK_FILE); /* connect to server  */

    if (connect(client_fd, (struct sockaddr *)&addr,
                sizeof(addr)) == -1) {
        perror("connect");
        goto fail;
    }

    msg->type = 0;

    if (send(client_fd, msg, sizeof(msg), 0) == -1) {
        perror("send");
        goto fail;
    }

    if ((len = recv(client_fd, msg, MAX_BUF_LEN, 0)) < 0) {
        perror("recv");
        goto fail;
    }

    if (msg->len >= MAX_MSG_LEN ) {
        /* cast to original struct  */
        st_msg = (struct test_send_struct *) msg->data;
        printf("st_msg is %s\n", st_msg->msg);
    }


fail:
    if (client_fd >= 0) {
        close(client_fd);
    }

    unlink(CLIENT_SOCK_FILE);
    return 1;

}


ipc.h

#define MAX_MSG_LEN     16
#define MAX_BUF_LEN     32
#define SERVER_SOCK_FILE "/tmp/server.sock"
#define CLIENT_SOCK_FILE "/tmp/client.sock"

struct ipc_msg {
    unsigned int type;
    int len;
    char data[0];
};

struct test_send_struct {
    char msg[MAX_MSG_LEN];
};
     

kezeodsnx 發表在 痞客邦 PIXNET 留言(0) 人氣()