域套接字-多客户端实现

域套接字-多客户端实现

我们在linux 应用开发中,如果需要实现进程间通信的多客户端接口,就需要引入select 和epoll 相关机制了,本文介绍下epoll的功能的实现。
多客户端使用场景,比如我们需要开发一个库接口,提供给客户调用,那么使用域套接字实现进程间通信,就必须在service端引入多路复用,否则库功能就只能被一个进程使用了。

代码实现:

service端
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<string.h>
#include<sys/un.h>
#include<sys/epoll.h>

#define dbg_printf(...) printf("[%s.%d]",__func__,__LINE__);printf(__VA_ARGS__)
#define UNIX_SOCKET_FILE  "/home/linux/test/socket/temp.file"


static int sockfd = 0;
static struct sockaddr_un servaddr,cliaddr;


int main(int argc, const char *argv[])
{

        int ret = 0;
        int connfd = 0;

        sockfd = socket(AF_UNIX,SOCK_STREAM,0);
        if(sockfd < 0 )
        {
                dbg_printf("socket error \n");
                return -1;
        }

        if(access(UNIX_SOCKET_FILE,F_OK) == 0)
        {
                dbg_printf("remove unix socket file \n");
                remove(UNIX_SOCKET_FILE);
        }

        memset(&servaddr,0,sizeof(servaddr));
        servaddr.sun_family = AF_UNIX;
        strcpy(servaddr.sun_path,UNIX_SOCKET_FILE);

        if(0 != bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)))
        {
                dbg_printf("bind fail \n");
                close(sockfd);
                return -1;
        }

        if(0 != listen(sockfd,10))
        {
                dbg_printf("linsten fail \n");
                close(sockfd);
                return -1;
        }


        int clilen = sizeof(cliaddr.sun_family)+strlen(cliaddr.sun_path);
/*
        if((connfd = accept(sockfd,(struct sockaddr *)&cliaddr,(socklen_t *)&clilen)) == -1)
        {
                dbg_printf("accept fail \n");
                return -1;
        }
        dbg_printf("accept success connfd = %d \n",connfd);

*/
        char recvbuf[64];
        int n = 0;

        int epfd;
        epfd = epoll_create(100);

        struct epoll_event ev;

        ev.events= EPOLLIN;
        ev.data.fd = sockfd;
        //将sockfd 添加到 监控事件的表中
        epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&ev);

        int datafd = 0;

        int i = 0;
        struct epoll_event evrdy[100];

        while(1)
        {
                ret = epoll_wait(epfd,evrdy,100,-1);
                dbg_printf("ret = %d ",ret);

                for(i = 0;i < ret; i++)
                {
                        if(evrdy[i].data.fd == sockfd) //建立连接的文件描述符
                        {
                                dbg_printf("build new connect \n");
                                datafd = accept(sockfd,(struct sockaddr *)&cliaddr,&clilen);

                                ev.events = EPOLLIN;
                                ev.data.fd = datafd;
                                //将sockfd 添加到 监控事件的表中
                                epoll_ctl(epfd,EPOLL_CTL_ADD,datafd,&ev);
                        }
                        else  //进程间通信描述符
                        {
                                dbg_printf("recv data \n");
                                memset(recvbuf,0,sizeof(recvbuf));
                                n = recv(evrdy[i].data.fd,recvbuf,sizeof(recvbuf),0);
                                if(n == -1)
                                {
                                        dbg_printf("recv error \n");
                                }
                                else if(n == 0)
                                {
                                        epoll_ctl(epfd,EPOLL_CTL_DEL,evrdy[i].data.fd,NULL);
                                        close(evrdy[i].data.fd);
                                        dbg_printf("client exit \n");
                                }
                                else if(n > 0)
                                {
                                        printf("service recvbuf is %s \n",recvbuf);

                                        send(evrdy[i].data.fd,"ok",strlen("ok"),0);
                                }
                        }
                }
        }

        close(sockfd);

        return 0;
}

client端

#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<string.h>
#include<sys/un.h>

#define dbg_printf(...) printf("[%s.%d]",__func__,__LINE__);printf(__VA_ARGS__)
#define UNIX_SOCKET_FILE  "/home/linux/test/socket/temp.file"


static int sockfd = 0;
static struct sockaddr_un servaddr,cliaddr;


int main(int argc, const char *argv[])
{

        int ret = 0;
        int connfd = 0;

        sockfd = socket(AF_UNIX,SOCK_STREAM,0);
        if(sockfd < 0 )
        {
                dbg_printf("socket error \n");
                return -1;
        }

        memset(&servaddr,0,sizeof(servaddr));
        servaddr.sun_family = AF_UNIX;
        strcpy(servaddr.sun_path,UNIX_SOCKET_FILE);


        int serlen = sizeof(servaddr.sun_family)+strlen(servaddr.sun_path);
        if(connect(sockfd,(struct sockaddr *)&servaddr,serlen) == -1)
        {
                dbg_printf("connect fail \n");
                close(sockfd);
                return -1;
        }

        dbg_printf("conect success \n");

        char recvbuf[64];
        char sendbuf[64];

        while(1)
        {
                memset(recvbuf,0,sizeof(recvbuf));
                memset(sendbuf,0,sizeof(sendbuf));

                strcpy(sendbuf,"i love you");

                send(sockfd,sendbuf,strlen(sendbuf),0);

                recv(sockfd,recvbuf,sizeof(recvbuf),0);

                dbg_printf("recv is %s \n",recvbuf);

                sleep(5);

        }

        close(sockfd);

        return 0;
}

实例测试:

编译上面文件为service 和client
client 我修改 发送内容 hello world 和 i love you ,编译生成client1 和client2,客户端与service通信, 测试如下
域套接字-多客户端实现

上一篇:CF468C Hack it! 超详细解答


下一篇:CF468C Hack it!