這次有兩個主題:
1. unix domain socket IPC
2. 傳structure
先看流程圖
使用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];
};
留言列表