1. UNIX域协议
利用socket 编程接口实现本地进程间通信
UNIX域协议套接字:可以使用TCP,也可以使用UDPSOCK_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) connectstruct 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. socketint 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. sendtochar 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. recvfromchar 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. closeclose(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. socketint 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. recvfromchar 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. sendtochar buff[250] = {0};scanf("%s", buff);int w = sendto(sockfd, buff, strlen(buff), 0, (struct sockaddr *)&cAddr, addrlen);printf("w = %d\n", w);}// 5. closeclose(sockfd);return 0; }