linux 本地socket通信
在linux中的进程间通信,不仅仅有消息队列,共享内存,管道,等!
本地socket也是不错的机制,效率只比消息队列低一点。
#include <ctype.h>
#include <dlfcn.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <sys/mman.h>
#define ALOGD printf
#define ALOGE printf
#define ALOGI printf
int create_socket(const char *name) {
struct sockaddr_un addr;
int sockfd, ret;
sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
if(sockfd < 0) {
ALOGD("Failed to open socket '%s': %s\n", name, strerror(errno));
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", name);
ret = unlink(addr.sun_path);
if(ret != 0 && errno != ENOENT) {
ALOGD("Failed to unlink old socket '%s': %s\n", name, strerror(errno));
close(sockfd);
return -1;
}
ret = bind(sockfd, (struct sockaddr *) &addr, sizeof(addr));
if(ret) {
ALOGD("Failed to bind socket '%s': %s\n", name, strerror(errno));
unlink(addr.sun_path);
close(sockfd);
return -1;
}
chmod(addr.sun_path, (mode_t) 0660);
ALOGD("Created socket %s with sockfd=%d\n", addr.sun_path, sockfd);
return sockfd;
}
/**
* Connect to server, Never return if connect fail
* @return Sock fd.
*/
int connect_server(const char *path) {
struct sockaddr_un server;
socklen_t alen = 0;
int sock, ret = 0;
if(path == NULL)
return -1;
sock = socket(PF_UNIX, SOCK_STREAM, 0);
if(sock < 0) {
ALOGE("Failed to open socket '%s': %s\n", path, strerror(errno));
return -1;
}
/** Initialize address structure */
memset(&server, 0, sizeof(struct sockaddr_un));
/** Set address family to unix domain sockets */
server.sun_family = AF_UNIX;
/** Set address to the requested pathname */
snprintf(server.sun_path, sizeof(server.sun_path), "%s", path);
/** Get length of pathname */
alen = strlen(server.sun_path) + sizeof(server.sun_family);
while(1) {
ret = connect(sock, (struct sockaddr *) &server, alen);
if(ret == 0)
break;
sleep(1);
}
ALOGI("Connected to server socket '%s': sock=%d", path, sock);
return sock;
}
通过create_socket的函数,建立本地socket节点。
例如:create_socket("/dev/socket/server_socket");
通过connect_server的函数,建立于服务节点的通信。
例如:connect_server("/dev/socket/server_socket");
static void *server_accepting_thread(void *) {
signal(SIGUSR1, signal_handler);
int client_fd;
struct sockaddr_un addr;
socklen_t addr_size = sizeof(addr);
int sockfd = create_socket(SOCKET);
if(sockfd < 0)
return NULL;
listen(sockfd, 8);
sem_post(&g_sem_accept_ready);
msg_t msg;
while(1) {
client_fd = -1;
memset(&msg, 0, sizeof(msg));
if((client_fd = accept(sockfd, (struct sockaddr *) &addr, &addr_size)) < 0) {
continue;
}
ALOGI("client_fd=%d connected\n", client_fd);
TEMP_FAILURE_RETRY(recv(client_fd, &msg, sizeof(msg), MSG_WAITALL));
ALOGI("client_fd=%d connected module is %s, msg is %s\n", client_fd, msg.module, msg.msg);
/*Set to module */
module_set_fd(msg.module, client_fd, msg.msg);
}
return NULL;
注意::
TEMP_FAILURE_RETRY(recv(client_fd, &msg, sizeof(msg), MSG_WAITALL));
它的功能: 不断地从套接口中接收客户端的“say_hello”数据直到成功为止。需要客户端实现。
保证通信正常。易于调试。
//使用MSG_WAITALL时,sockfd必须处于阻塞模式下,否则不起作用。
//所以MSG_WAITALL不能和MSG_NONBLOCK同时使用。
客户端可以通过recv接受数据
if((recv_size = recv(sock, msg, sizeof(msg_t), MSG_WAITALL)) < 0) {
ALOGE("%s:Recv fail: %s, received size:%d\n", __FUNCTION__, strerror(errno), recv_size);
break;
}