> 文章列表 > 本地套接字(domain)

本地套接字(domain)

本地套接字(domain)

        本地套接字是一种特殊类型的套接字,和 TCP/UDP 套接字不同。TCP/UDP 即使在本地地址通信,也要走系统网络协议栈,而本地套接字,严格意义上说提供了一种单主机跨进程间调用的手段,减少了协议栈实现的复杂度,效率比 TCP/UDP 套接字都要高许多。本地套接字是 IPC,也就是本地进程间通信的一种实现方式。

本地套接字的作用: 本地的进程间通信
可以实现 有关系的进程间的通信 和 没有关系的进程间的通信
本地套接字实现流程和网络套接字类似,一般采用TCP的通信流程。 

地址结构对比(本地对比网络)

struct sockaddr_in {
__kernel_sa_family_t sin_family; 			/* Address family */  	地址结构类型
__be16 sin_port;					 	    /* Port number */		端口号
struct in_addr sin_addr;					/* Internet address */	IP地址
};struct sockaddr_un {
__kernel_sa_family_t sun_family; 		/* AF_UNIX */			地址结构类型
char sun_path[UNIX_PATH_MAX]; 		    /* pathname */		socket文件名(含路径)
};

编程思想对比(本地对比网络)

本地套接字—进程间通信流程 

服务器端

1. 创建监听的套接字
      int lfd = socket(af_local, sock_stream, 0);
          第一个参数: AF_UNIX, AF_LOCAL

2. 监听的套接字绑定本地的 套接字文件-> server端
      struct sockaddr_un addr;
      // 绑定成功之后, 指定的sun_path中的套接字文件会自动生成
      bind(lfd, addr, len);

3. 监听
      listen(lfd, 100);

4. 等待并接受连接请求
      struct sockaddr_un cliaddr;
      int connfd  = accept(lfd, cliaddr, len);

5. 通信
      接收数据: read/recv
      发送数据: write/send

6. 关闭连接
      close();

客户端

1. 创建通信的套接字
      int fd = socket(af_local, sock_stream, 0);

2. 监听的套接字绑定本地的IP 端口
      struct sockaddr_un addr;
      // 绑定成功之后, 指定的sun_path中的套接字文件会自动生成
      bind(fd, addr, len);

3. 连接服务器
      struct sockaddr_un serveraddr;
      connect(fd, serveraddr, sizeof(serveraddr));

4. 通信
      接收数据: read/recv
      发送数据: write/send

5. 关闭连接

代码实现

/* server.c */
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <strings.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <stddef.h>#include "wrap.h"#define SERV_ADDR  "serv.socket"int main(void)
{int lfd, cfd, len, size, i;struct sockaddr_un servaddr, cliaddr;char buf[4096];lfd = Socket(AF_UNIX, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sun_family = AF_UNIX;strcpy(servaddr.sun_path, SERV_ADDR);len = offsetof(struct sockaddr_un, sun_path) + strlen(servaddr.sun_path);     /* servaddr total len */unlink(SERV_ADDR);                              /* 确保bind之前serv.sock文件不存在,bind会创建该文件 */Bind(lfd, (struct sockaddr *)&servaddr, len);           /* 参3不能是sizeof(servaddr) */Listen(lfd, 20);printf("Accept ...\\n");while (1) {len = sizeof(cliaddr);  //AF_UNIX大小+108Bcfd = Accept(lfd, (struct sockaddr *)&cliaddr, (socklen_t *)&len);len -= offsetof(struct sockaddr_un, sun_path);      /* 得到文件名的长度 */cliaddr.sun_path[len] = '\\0';                       /* 确保打印时,没有乱码出现 */printf("client bind filename %s\\n", cliaddr.sun_path);while ((size = read(cfd, buf, sizeof(buf))) > 0) {for (i = 0; i < size; i++)buf[i] = toupper(buf[i]);write(cfd, buf, size);}close(cfd);}close(lfd);return 0;
}
/* client.c */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <strings.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <stddef.h>#include "wrap.h"#define SERV_ADDR "serv.socket"
#define CLIE_ADDR "clie.socket"int main(void)
{int  cfd, len;struct sockaddr_un servaddr, cliaddr;char buf[4096];cfd = Socket(AF_UNIX, SOCK_STREAM, 0);bzero(&cliaddr, sizeof(cliaddr));cliaddr.sun_family = AF_UNIX;strcpy(cliaddr.sun_path,CLIE_ADDR);len = offsetof(struct sockaddr_un, sun_path) + strlen(cliaddr.sun_path);     /* 计算客户端地址结构有效长度 */unlink(CLIE_ADDR);Bind(cfd, (struct sockaddr *)&cliaddr, len);                                 /* 客户端也需要bind, 不能依赖自动绑定*/bzero(&servaddr, sizeof(servaddr));                                          /* 构造server 地址 */servaddr.sun_family = AF_UNIX;strcpy(servaddr.sun_path, SERV_ADDR);len = offsetof(struct sockaddr_un, sun_path) + strlen(servaddr.sun_path);   /* 计算服务器端地址结构有效长度 */Connect(cfd, (struct sockaddr *)&servaddr, len);while (fgets(buf, sizeof(buf), stdin) != NULL) {write(cfd, buf, strlen(buf));len = read(cfd, buf, sizeof(buf));write(STDOUT_FILENO, buf, len);}close(cfd);return 0;
}