UNIX 域协议
创始人
2024-11-15 14:40:50
0

1. UNIX域协议

利用socket 编程接口实现本地进程间通信

UNIX域协议套接字:可以使用TCP,也可以使用UDP

        SOCK_STREAM -----> TCP   面向字节流

        SOCK_DGRAM   -----> UDP  面向数据报


        UNIX域协议并不是一个实际的协议族,而是在单个主机上执行客户 / 服务器 通信的一种方式 (IPC的一种方法)

        UNIX域数据报 (SOCK_DGRAM)是可靠的,不会丢失消息

        IP协议中使用 IP地址 + 端口号标识客户端和服务端

        UNIX域协议使用普通文件系统中的路径名 (绝对路径) 标识客户端和服务端

如果这个路径不存在则创建后标识其为 客户/服务器 的地址 如果这个路径已经存在了则会报错:bind failed: Address already in use 所以在运行前先删掉,再去创建并且绑定  unlink(绝对路径名);

UNIX域协议的特点:

        和TCP比较,速度快,数据报不要传递到主机外,也不需要进行封包和拆包

        UNIX域协议使用一个绝对路径作为“IP”地址

#include

//vim /usr/include/linux/un.h #define UNIX_PATH_MAX 108  // Unix域协议的地址结构体的具体描述 // #include  struct sockaddr_un {     __kernel_sa_family_t sun_family; // 协议族     char sun_path[UNIX_PATH_MAX];     /*          Unix域协议地址,是以'\0'结束的本地文件系统中的绝对路径名,         如: "/tmp/xxx.socket"     */ }

编程方法:TCP / UDP

问题:客户端成功发送数据出去,服务端成功接收到数据,但是并没有成功将客户端的地址打印出来?

        客户端没有绑定地址。如果说服务端要向客户端发送数据的话,没有“IP”地址就没办法定位对方的具体位置了,所以要实现能获取客户端地址,则客户端需要绑定地址。

        使用UDP实现UNIX域协议如果客户端不绑定,服务器就不能发送信息给客户端

2. 代码实现

2.1 基于TCP实现UNIX域协议

unix_tcp_client.c

#include  #include  #include  #include  #include  #include  #include   #define SERVICEPATHNAME "/home/china/s" #define CLIENTPATHNAME "/home/china/c"  int main(int argc, char *argv[]) {      unlink(CLIENTPATHNAME);      // (1) socket:创建一个套接字     int sockfd =  socket(AF_UNIX, SOCK_STREAM, 0);     if (sockfd == -1) {         perror("unix socket failed");         return -1;     }      // (2) bind     // 需要一个网络地址结构体     struct sockaddr_un cAddr;     memset(&cAddr, 0, sizeof(cAddr));     cAddr.sun_family = AF_UNIX; // 协议族     strcpy(cAddr.sun_path, SLIENTPATHNAME);      int res = bind(sockfd, (struct sockaddr *)&cAddr, sizeof(cAddr));     if (res == -1) {         perror("unix bind failed");         close(sockfd);         return -1;     }      printf("bind success\n");      // (3) connect     struct sockaddr_un sAddr;     memset(&sAddr, 0, sizeof(sAddr));     sAddr.sun_family = AF_UNIX; // 协议族     strcpy(sAddr.sun_path, SERVICEPATHNMAE);      res = connect(sockfd, (struct sockaddr *)&sAddr, sizeof(sAddr));     if (res == -1) {         perror("unix connect failed");         return -1;     }      printf("unix connect succeed\n");      while (1) {          // (3) 进行通信,读写数据         char buf[250] = {0};         scanf("%s", buf);         int w = send(sockfd, buf, strlen(buf), 0);         printf("w = %d\n", w);              if (buf[0] == '#') {             break;         }          char buff[250] = {0};         int r = recv(sockfd, buff, 250, 0);          printf("r = %d,message = %s\n", r, buff);     }      // (4) 关闭socket套接字     close(sockfd);      return 0; } 

unix_tcp_server.c

#include  #include  #include  #include  #include  #include  #include   #define SERVICEPATHNAME "/home/china/s"  int main(int argc, char *argv[]) {      unlink(SERVICEPATHNMAE);      // (1) socket:创建一个套接字     int sockfd =  socket(AF_UNIX, SOCK_STREAM, 0);     if (sockfd == -1) {         perror("unix socket failed");         return -1;     }      // (2) bind:把一个套接字和网络地址绑定到一起     // 需要一个网络地址结构体     struct sockaddr_un sAddr;     memset(&sAddr, 0, sizeof(sAddr));     sAddr.sun_family = AF_UNIX; // 协议族     strcpy(sAddr.sun_path, SERVICEPATHNAME);      int res = bind(sockfd, (struct sockaddr *)&sAddr, sizeof(sAddr));     if (res == -1) {         perror("unix bind failed");         close(sockfd);         return -1;     }      printf("bind success\n");      // (3) listen:让套接字进入“监听模式”     res = listen(sockfd, 5);     if (res == -1) {         perror("unix listen failed");         close(sockfd);         return -1;     }      // 保存客户端的网络地址     struct sockaddr_un cAddr;     // 保存客户端的网络地址的长度     socklen_t addrlen = sizeof(cAddr);      // (4) 当没有客户端请求的时候,accept是阻塞的     int confd = accept(sockfd, (struct sockaddr *)&cAddr, &addrlen);     if (confd == -1) {         close(sockfd);         return -1;     }      printf("accept success\n");     printf("client path:%s\n", cAddr.sun_path);      while (1) {              // (5) 进行通信,读写数据         char buf[250] = {0};         int r = recv(confd, buf, 250, 0);         if (r != -1) {             printf("r = %d,messagee = %s\n", r, buf);         }          if (buf[0] == '#') {             close(confd);             break;         }         send(confd, "hello", sizeof("hello"), 0);     }      // (6) 关闭socket套接字:"四次挥手"     close(sockfd);      return 0; }
2.2 基于UDP实现UNIX域协议

unix_udp_client.c

#include  #include  #include  #include  #include  #include  #include   #define SERVICEPATHNAME "/home/china/s" #define CLIENTPATHNAME "/home/china/c"  int main(int argc, char *argv[]) {      unlink(CLIENTPATHNAME);      // 1. socket     int sockfd =  socket(AF_UNIX, SOCK_DGRAM, 0);     if (sockfd == -1) {         perror("udp socket failed");         return -1;     }      // 2. 必须bind     // 需要一个网络地址结构体     struct sockaddr_un cAddr;     memset(&cAddr, 0, sizeof(cAddr));     cAddr.sun_family = AF_UNIX; // 协议族     strcpy(cAddr.sun_path, CLIENTPATHNAME);      int res = bind(sockfd, (struct sockaddr *)&cAddr, sizeof(cAddr));     if (res == -1) {         perror("unix bind failed");         close(sockfd);         return -1;     }          // 需要一个网络地址,指定发给哪一个服务器     struct sockaddr_un sAddr;     memset(&sAddr, 0, sizeof(sAddr));     sAddr.sun_family = AF_UNIX; // 协议族     strcpy(sAddr.sun_path, SERVICEPATHNAME);      // 当服务器发信息给我时,保存该服务器的网络地址     struct sockaddr_un server_addr;     socklen_t addrlen = sizeof(server_addr);      while (1) {         // 2. sendto         char buf[250] = {0};         scanf("%s", buf);         int w =  sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&sAddr, sizeof(sAddr));         printf("w = %d\n", w);          if (buf[0] == '#') { // 退出条件             break;         }          // 3. recvfrom         char buff[250] = {0};         int r = recvfrom(sockfd, buff, 250, 0, (struct sockaddr*)&server_addr, &addrlen);         if (r > 0) {             printf("r = %d, buff = %s\n", r, buff);             printf("server path:%s\n", server_addr.sun_path);         }     }      // 4. close     close(sockfd);      return 0; }

unix_udp_server.c

#include  #include  #include  #include  #include  #include  #include   #define SERVICEPATHNMAE "/home/china/s"  int main(int argc, char *argv[]) {      unlink(SERVICEPATHNMAE);      // 1. socket     int sockfd =  socket(AF_UNIX, SOCK_DGRAM, 0);     if (sockfd == -1) {         perror("unix socket failed");         return -1;     }      // 2. bind     // 需要一个网络地址结构体     struct sockaddr_un sAddr;     memset(&sAddr, 0, sizeof(sAddr));     sAddr.sun_family = AF_UNIX; // 协议族     strcpy(sAddr.sun_path, SERVICEPATHNMAE);      int res = bind(sockfd, (struct sockaddr *)&sAddr, sizeof(sAddr));     if (res == -1) {         perror("unix bind failed");         close(sockfd);         return -1;     }      // 保存客户端的网络地址     struct sockaddr_un cAddr;     // 保存客户端的网络地址的长度     socklen_t addrlen = sizeof(cAddr);      while (1) {          // 3. recvfrom         char buf[250] = {0};         int r = recvfrom(sockfd, buf, 250, 0, (struct sockaddr *)&cAddr, &addrlen);         if (r > 0) {             printf("r = %d, buf = %s\n", r, buf);             printf("client path:%s\n", cAddr.sun_path);         }          // 4. sendto         char buff[250] = {0};         scanf("%s", buff);         int w = sendto(sockfd, buff, strlen(buff), 0, (struct sockaddr *)&cAddr, addrlen);         printf("w = %d\n", w);     }      // 5. close     close(sockfd);      return 0; }

相关内容

热门资讯

详细分析Java中的@Requ... 目录前言1. 基本知识2. 使用场景2.1 @RequestParam注解2.2 @...
【已解决】Python错误:T... 😎 作者介绍:我是程序员洲洲,一个热爱写作的非著名程序员...
【C++航海王:追寻罗杰的编程... 目录C++11(上)1 -> STL中的一些变化2 -> 右值引用和移动语义2.1 ...
Python数据容器——列表、... 作者:Insist--个人主页:insist--个人主页本文专栏...
隐私安全测试:保护您的数字世界   大家好,我是一名_全栈_测试开发工程师,已经开源一套【自动化测试框架...
在Jira中使用AI Jira已经可以使用AI功能了。如果您使用的是Jira Cloud,您需要请管理员在管...
【一图学技术】5.OSI模型和... OSI模型和TCP/IP模型关系图解 OSI模型和TCP/IP模型都是网络通信的参考模型࿰...
TCP半关闭过程 TCP半关闭过程简介tcp半关闭是指在一端发送完数据后,关闭发送通道,而...
公司的Spring框架接受MI... 接收方法:解决方案:先去掉@RequsetBody 因为使用&#...
【机器学习】探索图神经网络 (...   💎 欢迎大家互三:2的n次方_ ​💎1. 引言图结...