IPC之本地套接字

进程间通信,UNP2 这本经典的书籍讲的已经很清楚了,常见的进程间通信就是信号量 消息队列 共享内存,其实本地套接字更是一种进程间通信的手段,而且起码要比信号量更加直观。本文描述下基本的利用本地套接字来进行进程通信。

#define UNIX_PATH_MAX 108
 
struct sockaddr_un {
       sa_family_t sun_family; /* AF_UNIX */

       char sun_path[UNIX_PATH_MAX]; /* pathname */
};


可以看到这就是本地套接字的数据结构,110个字节,sun_path相当于socket的门牌号,或者地址,用于通信。我们知道,两个人通信,如果你知道对方的门牌号,那么你就能找到他,和他聊天。本地套接字也是一样,如果我是服务器,就在我门牌号这里等待别人来找我。

#include<stdio.h>

#include<stdlib.h>

#include<unistd.h>

#include<errno.h>

#include<string.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<sys/socket.h>

#include<sys/un.h>

#include<signal.h>



int pipe_process()

{

        struct sigaction newact,oldact;

        newact.sa_handler = SIG_IGN;

        sigemptyset(&newact.sa_mask);

        newact.sa_flags = 0;

        

        sigaction(SIGPIPE,&newact,&oldact);

        return 0;

}



int main()

{

                int server_sockfd,client_sockfd;

                int server_len,client_len;

                struct sockaddr_un server_address;

                struct sockaddr_un client_address;

                const char path_unix[] = "MY_SOCKET";

                int len_unix;

                char buf[1024];

                int n;



                unlink("MY_SOCKET");

                server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);



                server_address.sun_family = AF_UNIX;

                strncpy(server_address.sun_path, path_unix,sizeof(server_address.sun_path));

                server_len = sizeof(server_address);

                len_unix = SUN_LEN(&server_address);

                bind(server_sockfd,(struct sockaddr *)&server_address,server_len);

                
                pipe_process();
                listen(server_sockfd, 5);

                while(1){



                                printf("server waiting\n");

  
                                client_len = sizeof(client_address);

                                client_sockfd = accept(server_sockfd,(struct sockaddr *)&client_address, &client_len);

                

                                memset(buf,0,sizeof(buf)/sizeof(buf[0]));

                                n = read(client_sockfd,buf,1024);

                             if(n < 0)

                                {

                                 fprintf(stderr,"read failed\n");

                                        return -1;

                                }

                                fprintf(stderr,"recv : %s\n",buf);

                                close(client_sockfd);

                }

}


我们看下这几行代码

const char path_unix[] = "MY_SOCKET";

        unlink("MY_SOCKET");

        server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);

        server_address.sun_family = AF_UNIX;

        strncpy(server_address.sun_path, path_unix,sizeof(server_address.sun_path));

        server_len = sizeof(server_address);

        len_unix = SUN_LEN(&server_address);

        bind(server_sockfd,(struct sockaddr *)&server_address,server_len);

 

我先定义了一个门牌号,然后将我的套接字和门牌号绑定,这样的话,别人就能通过我的门牌号找到我了。这里插一

段,SUN_LEN是一个宏来告知sockaddr_un的有效长度,对于本例子,len_unix = 2 + 9 =11.

bind之前

root@libin:~/program/C/sock/af_unix# netstat -ap|grep -Ei "serv|prot"

Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name

Proto RefCnt Flags Type State I-Node PID/Program name 路径

unix 2 [ ] 流 394869 4090/server

bind之后(当然也执行了listen)

root@libin:~/program/C/sock/af_unix# netstat -ap|grep -Ei "serv|prot"

Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name

Proto RefCnt Flags Type State I-Node PID/Program name 路径

unix 2 [ ACC ] 流 LISTENING 394869 4090/server MY_SOCKET

我们看到我们的套接字有了门牌号,这样客户端想要连接的话,就可以根据门牌号,按图索骥的找到我们了。

下面是客户端的代码:

#include <stdio.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/un.h>

#define UNIX_DOMAIN "MY_SOCKET"



int main(void)

{

                int connect_fd;

                int ret;

                char snd_buf[1024];

                int i;

                static struct sockaddr_un srv_addr;

               

                connect_fd=socket(PF_UNIX,SOCK_STREAM,0);

                if(connect_fd<0)

                {

                                fprintf(stderr,"cannot create communication socket");

                                return 1;

                }

                srv_addr.sun_family=AF_UNIX;

                strcpy(srv_addr.sun_path,UNIX_DOMAIN);

               

                ret=connect(connect_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));

                if(ret==-1)

                {

                                perror("cannot connect to the server");

                                close(connect_fd);

                                return 1;

                }

                memset(snd_buf,0,1024);

                strcpy(snd_buf,"hello server !");

               

                write(connect_fd,snd_buf,sizeof(snd_buf));

                close(connect_fd);

                return 0;

}

 

可以看到,关键部分就是加粗的那部分代码,客户端根据sun_path就能找到服务器,然后去连接服务器。我们看到客户端给服务器进程发了个hello server就退出了。实际工程代码中,可以发送双方约定好的很复杂的数据,告诉服务器进程去处理客户端进程提交的数据。   

 OK,看下效果:    先启动服务器进程,可以看到服务器在等待客户来连接。root@libin:~/program/C/sock/af_unix# ./server

server waiting   

然后启动客户端进程,客户段打了招呼就退出了,

root@libin:~/program/C/sock/af_unix# ./client

root@libin:~/program/C/sock/af_unix#  

看下服务器的反应:服务器的确是收到了发来的语句,同时继续等待。

recv : hello server !

server waiting

 转载自:http://blog.chinaunix.net/uid-24774106-id-3165204.html

 


 
 
 
 
 
 
 
 
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值