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;
        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章