UNIX 域协议

avatar
作者
猴君
阅读量: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 <sys/un.h>

//vim /usr/include/linux/un.h #define UNIX_PATH_MAX 108  // Unix域协议的地址结构体的具体描述 // #include <sys/un.h> 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 <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/un.h>  #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 <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/un.h>  #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 <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/un.h>  #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 <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/un.h>  #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; }

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!