linux 本地socket通信

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;
        }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值