UNIX网络编程笔记(11)—UNIX域套接字

来源:互联网 发布:rolling girl动作数据 编辑:程序博客网 时间:2024/06/05 03:16

UNIX网络编程笔记(11)—UNIX域套接字

1.简介

Unix域协议并不是一个实际的协议族,而是在单个主机上执行客户/服务器通讯的一种方式,单个主机上执行通信,也就是所谓的进行间通信(IPC),所以Unix域套接字协议可以视作IPC方法之一。

Unix域提供两类套接字:字节流套接字(类似TCP)和数据报套接字(类似DUP)。

Unix域中用于标识客户和服务器的协议地址是普通文件系统中的路径名(但需要和Unix域套接字关联起来),否则无法读写这些文件。回忆一蛤,IPv4的协议地址由一个32位地址和16位端口号构成,IPv6协议地址则由一个128位地址和16位端口号组成。


2.Unix域套接字地址结构

#include <sys/un.h>struct sockaddr_un {    sa_family_t sum_family;// AF_LOCAL或者AF_UNIX    char sun_path[104];//字符串指代路径(null终止)};

sun_path表示与套接字关联的地址,以NULL结尾,如果未指定地址通则通过以空字符串作为路径名指示,也就是说sun_path[0]值为0,这个效果就好像Ipv4的INADDR_ANY和IPv6的ADDR_ANY_INIT


3.socketpair函数

这个是UNIX域套接字特有的函数,它创建两个素侯连接起来的套接字。

#include <sys/socket.h>int socketpair(int family , int type , int protocol ,int sockfd[2]);//返回:成功则为0,出错则为-1

3.1参数说明

family: 为AF_LOCAL或者AF_UNIX
type:既可以是SOCK_STREAM也可以是SOCK_DGRAM
protocol:必须为0。
sockfd[2]:新创建的两个套接字别在sockfd[0]和sockfd[1]中返回。

当设置type参数为SOCK_STREAM时,得到的结果就叫做流管道这与pipe创建的的普通UNIX管道类似了。差别在于流管道是全双工的,也就是说,两个描述符既可读也可写。回忆一蛤,用pipe创建的匿名管道,pipefd[0]用于读操作,pipefd[1]用于写操作。


4.UNIX域套接字编程

还是根据UNP1中的代码写的,主要工作就是把包裹函数拆开。

4.1 Unix域字节流客户/服务器程序

跟TCP客户服务程序类似,不过在bind步骤中,是将特定的path与套接字绑定。

代码

服务器程序

//unixdomainserv.c#include <sys/un.h>#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/wait.h>#include <stdio.h>#include <netinet/in.h>#include <unistd.h>#include <string.h>#include <signal.h>#include <errno.h>#define UNIXDOMAIN_PATH "/tmp/unix.str"#define MAXLEN 1024void sig_child(int);void str_echo(int );typedef void(*sig_handle)(int);//handleint main(int argc ,char **argv){    int listenfd;    int connfd;    socklen_t clilen;    struct sockaddr_un cliaddr,servaddr;    pid_t childpid;    if((listenfd = socket(AF_LOCAL,SOCK_STREAM,0))<0)//socket    {        printf("socket error\r\n");        return -1;    }    unlink(UNIXDOMAIN_PATH);//delete file    bzero(&servaddr,sizeof(servaddr));//    memset(&servaddr,0x00,sizeof(servaddr));    servaddr.sun_family=AF_LOCAL;    strcpy(servaddr.sun_path,UNIXDOMAIN_PATH);    if(bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr))<0)//bind    {        printf("bind error\r\n");        return -1;    }    if(listen(listenfd,5)<0)//listen    {        printf("listen error\r\n");        return -1;    }    sig_handle handle1 = sig_child;    signal(SIGCHLD,handle1);    while(1)    {        clilen = sizeof(cliaddr);        if((connfd=accept(listenfd,(struct sockaddr *)&cliaddr,&clilen))<0)        {            printf("accept error\r\n");        }        if((childpid= fork())==0)//child process        {            close(listenfd);            str_echo(connfd);            return 0;        }        close(connfd);//parent  close connfd    }    return 0;}void str_echo(int connfd){    ssize_t nread;    char readbuff[MAXLEN];    memset(readbuff,0x00,sizeof(readbuff));    while((nread=read(connfd,readbuff,MAXLEN))>0)    {        write(connfd,readbuff,strlen(readbuff));        memset(readbuff,0x00,sizeof(readbuff));    }}void sig_child(int signo){    pid_t pid;    int stat;#if 1     while((pid=waitpid(-1,&stat,WNOHANG))>0)    printf("waitpid:child terminated,pid=%d\r\n",pid);#endif    return ;}

客户端程序

#include <sys/un.h>#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/wait.h>#include <stdio.h>#include <netinet/in.h>#include <unistd.h>#include <string.h>#include <signal.h>#define UNIXDOMAIN_PATH "/tmp/unix.str"#define MAXLEN 1024void str_cli(FILE*,int);int main(int argc, char **argv){    int sockfd;    struct sockaddr_un servaddr;    if((sockfd = socket(AF_LOCAL,SOCK_STREAM,0))<0)//socket    {        printf("socket error\r\n");        return -1;    }    bzero(&servaddr,sizeof(servaddr));//    memset(&servaddr,0x00,sizeof(servaddr));    servaddr.sun_family=AF_LOCAL;//or AF_UNIX    strcpy(servaddr.sun_path,UNIXDOMAIN_PATH);    if(connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)//connect    {        printf("conncet error\r\n");        return -1;    }    str_cli(stdin,sockfd);    return 0;}void str_cli(FILE*fp,int sockfd){    int nread;    int nwrite;    char readbuff[MAXLEN];    while( fgets(readbuff,sizeof(readbuff),fp)!=NULL)    {        if( (nwrite= write(sockfd,readbuff,strlen(readbuff)))<0)        {            printf("write error \r\n");            return ;        }        memset(readbuff,0x00,sizeof(readbuff));        if(( nread= read(sockfd,readbuff,sizeof(readbuff)))<0)        {            printf("read error \r\n");            return ;        }        fputs(readbuff,stdout);    }}

4.2 Unix域数据报客户/服务器程序

与UDP程序类似,但是客户端需要有一些改变:

当使用Unix域数据报协议时候,我们必须显示的bind一个路径名到我们到套接字,这样服务器才会有能回射应答的路径名。在书中用了tmpnam赋值一个临时路径名,但是在编译的时候说该函数已经不用了,取而代之的是mkstemp

代码

服务器程序

#include <sys/un.h>#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/wait.h>#include <stdio.h>#include <netinet/in.h>#include <unistd.h>#include <string.h>#include <signal.h>#include <errno.h>#define UNIXDOMAIN_PATH "/tmp/unix.dg"#define MAXLEN 1024#define MAXLINE 1024void dg_echo(int,struct sockaddr *,socklen_t );int main(int argc ,char **argv){    int sockfd;    struct sockaddr_un cliaddr,servaddr;    if((sockfd = socket(AF_LOCAL,SOCK_DGRAM,0))<0)//socket    {        printf("socket error\r\n");        return -1;    }    unlink(UNIXDOMAIN_PATH);//delete file    bzero(&servaddr,sizeof(servaddr));//    memset(&servaddr,0x00,sizeof(servaddr));    servaddr.sun_family=AF_LOCAL;    strcpy(servaddr.sun_path,UNIXDOMAIN_PATH);    if(bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr))<0)//bind    {        printf("bind error\r\n");        return -1;    }    dg_echo(sockfd,(struct sockaddr *)&cliaddr,sizeof(cliaddr));    return 0;}#if 1void dg_echo(int sockfd ,struct sockaddr* pcliaddr,socklen_t clilen){    char buf[MAXLEN];    int n;    socklen_t len ;    while(1)    {        len = clilen;        if((n=recvfrom(sockfd,buf,MAXLEN,0,pcliaddr,&len))<0)        {            printf("recvfrom error\r\n");            return ;        }        sendto(sockfd,buf,n,0,pcliaddr,len);    }}#endif

客户端程序

#include <sys/un.h>#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/wait.h>#include <stdio.h>#include <netinet/in.h>#include <unistd.h>#include <string.h>#include <signal.h>#include <stdlib.h>#define UNIXDOMAIN_PATH "/tmp/unix.dg"#define MAXLEN 1024void dg_cli(FILE*,int,const struct sockaddr *,socklen_t);int main(int argc, char **argv){    int sockfd;    struct sockaddr_un servaddr;    struct sockaddr_un cliaddr;    if((sockfd = socket(AF_LOCAL,SOCK_DGRAM,0))<0)//socket    {        printf("socket error\r\n");        return -1;    }    bzero(&cliaddr,sizeof(cliaddr));//    memset(&servaddr,0x00,sizeof(servaddr));    cliaddr.sun_family=AF_LOCAL;    char temp[]="template_XXXXXX";    int fd = mkstemp(temp);    strcpy(cliaddr.sun_path,temp);    unlink(temp);    close(fd);    if(bind(sockfd,(struct sockaddr*)&cliaddr,sizeof(cliaddr))<0)//bind    {        printf("conncet error\r\n");        return -1;    }    bzero(&servaddr,sizeof(servaddr));    servaddr.sun_family=AF_LOCAL;    strcpy(servaddr.sun_path,UNIXDOMAIN_PATH);    dg_cli(stdin,sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));    return 0;}void dg_cli(FILE*fp,int sockfd,const struct sockaddr*pservaddr,socklen_t servlen){    int n;    char sendbuff[MAXLEN];    char recvbuff[MAXLEN+1];    while(fgets(sendbuff,MAXLEN,fp)!=NULL)    {        //指定服务器套接字结构直接sendto        sendto(sockfd,sendbuff,strlen(sendbuff),0,pservaddr,servlen);        if((n=recvfrom(sockfd,recvbuff,MAXLEN,0,NULL,NULL))<=0)        {            printf("recvfrom error\r\n");            return ;        }        recvbuff[n]='\0';//防止越界        fputs(recvbuff,stdout);//输出回射数据    }}

4.3 附录:Makefile

PROGS =unixdomainserv unixdomaincli unixdomainserv2 unixdomaincli2CLEANFILES = core core.* *.core *.o temp.* *.out typescript* \        *.lc *.lh *.bsdi *.sparc *.uwall :${PROGS}CFLAGS+=-g unixdomainserv:unixdomainserv.o    ${CC} ${CFLAGS} -o $@ $^unixdomaincli:unixdomaincli.o    ${CC} ${CFLAGS} -o $@ $^unixdomainserv2:unixdomainserv2.o    ${CC} ${CFLAGS} -o $@ $^unixdomaincli2:unixdomaincli2.o    ${CC} ${CFLAGS} -o $@ $^    @rm *oclean:    rm -f ${PROGS} ${CLEANFILES}

5.参考

1.《UNP1》

1 0
原创粉丝点击