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》
- UNIX网络编程笔记(11)—UNIX域套接字
- 《UNIX网络编程》笔记——套接字选项
- 《网络编程》Unix 域套接字
- 网络编程练习-unix域套接字
- UNIX网络编程:套接字
- UNIX网络编程笔记(2)—套接字编程简介
- UNIX网络编程笔记(3)—基本TCP套接字编程
- 《UNIX环境高级编程》笔记--UNIX域套接字
- 《UNIX环境高级编程》笔记--UNIX域套接字
- 《UNIX环境高级编程》笔记--UNIX域套接字
- UNIX网络编程——套接字选项(SO_REUSEADDR)
- UNIX网络编程——套接字选项(setsockopt)
- 《UNIX网络编程》学习笔记:基本TCP套接字编程
- UNIX网络编程笔记 第三章 套接字编程简介
- UNIX网络编程——UNIX域套接字编程和socketpair 函数
- Unix网络编程学习笔记【1】套接字地址结构
- Unix网络编程学习笔记【1】套接字地址结构
- UNIX网络编程笔记 第七章 套接字选项
- Linux -- 档案与目录管理
- Android自定义权限
- 【整理】getElementByID,getElementsByName,getElemtsByTagName的区别
- [Kubernetes]Docker的overlay网络模型
- java语言基础入门——多线程
- UNIX网络编程笔记(11)—UNIX域套接字
- Android高效的加载大图片
- Linux -- 磁盘与文件系统
- 51nod 1069 Nim游戏
- SqlMap用户手册
- StackOverflow程序员推荐:每个程序员都应读的30本书
- Linux14.04下安装网易云音乐和搜狗输入法(太棒了!!!)
- 循环队列与链队列的优劣势
- 每次rand出来都是41?说好的随机数呢?!