- 域套接字属于本机 IPC 进程间通信,只用于同一主机内多进程通信,不支持跨主机。
- 无需 IP 地址、端口号;通信载体是 Linux 下s 类型套接字文件。
- 数据经由内核空间完成进程之间的数据传输。
域套接字通信也分为流式域套接字和报式域套接字。
#include<sys/types.h>/* See NOTES */#include<sys/socket.h>intsocket(intdomain,inttype,intprotocol);功能:为通信创建一个端点,并返回该端点对应的文件描述符,文件描述符的使用原则是最小未分配 原则 参数1:协议族,常用的协议族如下 Name Purpose Man page AF_UNIX,AF_LOCAL 本地通信,同一主机的多进程通信 具体内容查看 man7unix AF_INET 提供IPv4的相关通信方式 具体内容查看 man7ip AF_INET6 提供IPv6的相关通信方式 具体内容查看 man7ipv6 参数2:通信类型,指定通信语义,常用的通信类型如下 SOCK_STREAM 支持TCP面向连接的通信协议 SOCK_DGRAM 支持UDP面向无连接的通信协议 参数3:通信协议,当参数2中明确指定特定协议时,参数3可以设置为0,但是有多个协议共同使用 时,需要用参数3指定当前套接字确定的协议 返回值:成功返回创建的端点对应的文件描述符,失败返回-1并置位错误码#include<sys/types.h>/* See NOTES */#include<sys/socket.h>intbind(intsockfd,conststructsockaddr*addr,socklen_t addrlen);功能:为套接字分配名称,给套接字绑定ip地址和端口号 参数1:要被绑定的套接字文件描述符 参数2:通用地址信息结构体,对于不同的通信域而言,使用的实际结构体是不同的,该结构体的目的是为了强制类型转换,防止警告 通信域为:AF_UNIX而言,本地通信structsockaddr_un{sa_family_t sun_family;/* 通信域:AF_UNIX */charsun_path[UNIX_PATH_MAX];/* 通信使用的文件 */要求套接字文件不存在};参数3:参数2的大小 返回值:成功返回0,失败返回-1并置位错误码判断一个文件是否存在于文件系统函数
#include<unistd.h>intaccess(constchar*pathname,intmode);功能:判断给定的文件是否具有给的的权限 参数1:要被判断的文件描述符 参数2:要被判断的权限 R_OK:读权限 W_OK:写权限 X_OK:执行权限 F_OK:是否存在 返回值:如果要被判断的权限都存在,则返回0,否则返回-1并置位错误码删除一个文件系统中的文件函数
#include<unistd.h>intunlink(constchar*path);功能:删除指定的文件 参数:要删除的文件路径 返回值:成功删除返回0,失败返回-1并置位错误码1、流式域套接字实现
intmain(intargc,constchar*argv[]){//1、创建用于通信的客户端套接字文件描述符intcfd=socket(AF_UNIX,SOCK_STREAM,0);if(cfd==-1){perror("socket error");return-1;}printf("socket success cfd=%d\n",cfd);//2、绑定ip地址和端口号 如果没有绑定,系统也不会自动绑定,会给的一个随机文件if(access("./linux",F_OK)==0){//说明文件已经存在,需要将其进行删除操作if(unlink("./linux")==-1){perror("unlink error");return-1;}}//2.1、填充要绑定的地址信息结构体structsockaddr_uncun;cun.sun_family=AF_UNIX;stcpy(cun.sun_path,"./linux");//2.2、绑定工作if(bind(cfd,(structsockaddr*)&cun,sizeof(cun))==-1){perror("bind error");return-1;}printf("bind success\n");//3、连接服务器//3.1 填充要连接的服务器地址信息结构体structsockaddr_unsun;sun.sun_family=AF_UNIX;//通信域strcpy(sun.sun_path,"./unix");//服务器套接字文件//3.2 连接工作if(connect(cfd,(structsockaddr*)&sun,sizeof(sun))==-1){perror("connect error");return-1;}printf("连接成功\n");//4、数据收发charwbuf[128]="";while(1){//清空容器bzero(wbuf,sizeof(wbuf));//从终端获取数据fgets(wbuf,sizeof(wbuf),stdin);//0wbuf[strlen(wbuf)-1]=0;//将数据发送给服务器if(send(cfd,wbuf,sizeof(wbuf),0)==-1){perror("send error");return-1;}//接受服务器发送过来的消息if(recv(cfd,wbuf,sizeof(wbuf),0)==0){printf("对端已经下线\n");break;}printf("收到服务器消息为:%s\n",wbuf);}//5、关闭套接字close(cfd);std::cout<<"Hello, World!"<<std::endl;return0;}Unix 域套接字对比网络 socket
- 不用 IP、端口,使用套接字文件标识通信端点。
- 通信域:AF_UNIX;地址结构体:struct sockaddr_un。
- bind绑定的套接字文件,必须预先不存在。
- 客户端不手动 bind,系统不会自动分配套接字文件,不会生成乱码文件名。
2、报式域套接字实现
- 服务器端实现
intmain(intargc,constchar*argv[]){//1、创建用于通信的套接字文件描述符intsfd=socket(AF_UNIX,SOCK_DGRAM,0);//SOCK_DGRAM表示基于udp通信方式if(sfd==-1){perror("socket error");return-1;}printf("socket success sfd = %d\n",sfd);//3//2、绑定套接字文件//判断套接字文件是否存在if(access("./unix",F_OK)==0){//说明文件已经存在,需要将其进行删除操作if(unlink("./unix")==-1){perror("unlink error");return-1;}}//2.1 填充要绑定的ip地址和端口号结构体structsockaddr_unsun;sun.sun_family=AF_UNIX;//通信域strcpy(sun.sun_path,"./unix");//套接字文件//2.2 绑定工作//参数1:要被绑定的套接字文件描述符//参数2:要绑定的地址信息结构体,需要进行强制类型转换,防止警告//参数3:参数2的大小if(bind(sfd,(structsockaddr*)&sun,sizeof(sun))==-1){perror("bind error");return-1;}printf("bind success\n");//3、数据收发charrbuf[128]="";//定义容器接收对端的地址信息结构体structsockaddr_uncun;socklen_t socklen=sizeof(cun);while(1){//清空容器bzero(rbuf,sizeof(rbuf));//从客户端中读取消息if(recvfrom(sfd,rbuf,sizeof(rbuf),0,(structsockaddr*)&cun,&socklen)==-1){perror("recvfrom error");return-1;}printf("[%s]:%s\n",cun.sun_path,rbuf);//加个笑脸发给客户端strcat(rbuf,"*_*");//将数据发送给客户端sendto(sfd,rbuf,strlen(rbuf),0,(structsockaddr*)&cun,sizeof(cun));printf("发送成功\n");}//4、关闭套接字close(sfd);std::cout<<"Hello, World!"<<std::endl;return0;}- 客户端端实现
#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/socket.h>#include<sys/un.h>#include<string.h>intmain(intargc,constchar*argv[]){//1、创建用于通信的套接字文件描述符intcfd=socket(AF_UNIX,SOCK_DGRAM,0);if(cfd==-1){perror("socket error");return-1;}printf("socket success cfd = %d\n",cfd);//填充服务端的地址信息(目标地址,不需要bind)structsockaddr_unsun_server;sun_server.sun_family=AF_UNIX;strcpy(sun_server.sun_path,"./unix");charwbuf[128]="";charrbuf[128]="";while(1){bzero(wbuf,sizeof(wbuf));bzero(rbuf,sizeof(rbuf));printf("请输入要发送的数据:");fgets(wbuf,sizeof(wbuf),stdin);//去掉fgets读到的换行符wbuf[strcspn(wbuf,"\n")]='\0';//发送数据给服务端if(sendto(cfd,wbuf,strlen(wbuf),0,(structsockaddr*)&sun_server,sizeof(sun_server))==-1){perror("sendto error");return-1;}//接收服务端回显应答structsockaddr_uncun;socklen_t socklen=sizeof(cun);if(recvfrom(cfd,rbuf,sizeof(rbuf),0,(structsockaddr*)&cun,&socklen)==-1){perror("recvfrom error");return-1;}printf("服务器回复:%s\n",rbuf);//输入quit退出if(strcmp(wbuf,"quit")==0){break;}}close(cfd);return0;}