嵌入式linux网络编程,UNIX域套接字,AF_LOCAL,PF_LOCAL,PF_UNIX,,A

2019-07-13 08:44发布

文章目录

1,UNIX域套接字

用于本地进程间的通信
  1. socket同样可以用于本地通信
  2. 创建套接字时使用本地协议PF_UNIX(或PF_LOCAL)。
    ·socket(AF_LOCAL, SOCK_STREAM, 0) /流式套接字/
    · socket(AF_LOCAL, SOCK_DGRAM, 0) /数据报套接字/
PF_INET 和 AF_INET的区别:http://blog.sina.com.cn/s/blog_8043547601013eoc.html
所以在windows中AF_INET与PF_INET完全一样
而在Unix/Linux系统中,在不同的版本中这两者有微小差别
对于BSD,是AF,对于POSIX是PF
  1. 分为流式套接字和用户数据报套接字
  2. 和其他进程间通信方式相比使用方便、效率更高
  3. 常用于前后台进程通信
Linux下的进程间通信机制 应用 早期UNIX进程间通信方式
(很多是从Unix继承的) 无名管道(pipe) 本地通信,用于一台计算机内部不同进程之间的通信 有名管道 (fifo) 信号(signal) System V IPC
(系统5的IPC机制) 共享内存(share memory) 消息队列(message queue) 信号灯集(semaphore set) 套接字(socket) 既可以进行本地通信,更多的是多台主机之间通过网络通信 易用性:消息队列 > unix域套接字 > 管道 > 共享内存(经常要和信号量一起使用)
效率:共享内存 > unix域套接字 > 管道 > 消息队列
常用:共享内存、unix域套接字 异步通信:信号 同步和互斥(做资源保护):信号量
  1. 本地地址结构
    struct sockaddr_un //
    {
    sa_family_t sun_family;
    char sun_path[108]; // 套接字文件的路径
    };
  2. 填充地址结构
    struct sockaddr_un myaddr;
    bzero(&myaddr, sizeof(myaddr));
    myaddr.sun_family = AF_UNIX; strcpy(myaddr.sun_path, “/tmp/mysocket”);

2,UNIX域套接字模型

应用程序 UNIX域(流式)套接字 UNIX域(用户数据报)套接字 服务器端 客户端 #include /* See NOTES */ #include int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
  • 此处addr是一个本地地址,结构体为struct sockaddr_un
#define UNIX_PATH_MAX 108 //大小为96~108 struct sockaddr_un { sa_family_t sun_family; /* AF_UNIX */ char sun_path[UNIX_PATH_MAX]; /* pathname */ };
  • pathname 为域套接字的文件路径
    ·必须事先不存在(临时在内存中创建一个文件)
    ·一般是绝对路径

3,UNIX域套接字 — 示例

3.1,net.h

#ifndef __NET_H__ #define __NET_H__ #include #include #include #include #include #include #include #include #include #include #include #include #define UNIX_DOMAIN_FILE "/tmp/my_domain_file.1" #define BACKLOG 5 #define QUIT_STR "quite" #define SERV_RESP_STR "Server:" #endif

3.2,client.c

/* ./client unix_domaun_file */ #include "net.h" void usage(char *s) { printf("Usage: %s ",s); } int main(int argc, const char *argv[]) { int fd; if(argc != 2) { usage((char *)argv[0]); exit(1); } /* 1 创建socket fd */ if((fd = socket(AF_LOCAL,SOCK_STREAM,0)) < 0) { perror("socket"); exit(-1); } /* 2 连接服务器 */ /* 2.1 填充struct sockaddr_un结构体变量*/ struct sockaddr_un sun; bzero(&sun,sizeof(sun)); sun.sun_family = AF_LOCAL; /* 确保UNIX_DOMAun_FILE所指向的文件存在且可写,否则退出 */ if(access(UNIX_DOMAIN_FILE,F_OK|W_OK) < 0) { exit(-1); } strncpy(sun.sun_path,argv[1],strlen(argv[1])); /* 2.2 连接服务器*/ if(connect(fd,(struct sockaddr *)&sun,sizeof(sun)) < 0) { perror("connect"); goto _error1; } printf("client starung ... OK! "); fd_set rset; int maxfd; struct timeval tout; char buf[BUFSIZ]; int ret = -1; while(1) { FD_ZERO(&rset); FD_SET(0,&rset); FD_SET(fd,&rset); maxfd = fd; tout.tv_sec = 5; tout.tv_usec = 0; select(maxfd+1,&rset,NULL,NULL,&tout); if(FD_ISSET(0,&rset))//标准输入里面是不是有输入 { /* 读取键盘输入,发送到网络套接字fd */ bzero(buf,BUFSIZ); do { ret = read(0,buf,BUFSIZ-1); }while(ret <0 && EINTR == errno); if(ret < 0) { perror("read"); continue ; } if(ret == 0)//没读到数据 { continue; } if(write(fd,buf,strlen(buf)) < 0) { perror("write() to socket"); continue ; } if(strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)) == 0)//退出在发送之后 { printf("client is existung! "); break; } } if(FD_ISSET(fd,&rset))//服务器发送了数据过来 { /* 读取套接字数据,处理 */ bzero(buf,BUFSIZ); do { ret = read(fd,buf,BUFSIZ-1); }while(ret <0 && EINTR == errno); if(ret < 0) { perror("read from socket"); continue ; } if(ret == 0)//从套接字中读到的数据个数小于0,说明服务器关闭 { break ; } printf("server said: %s",buf); if((strlen(buf) > strlen(SERV_RESP_STR)) && strncasecmp(buf+strlen(SERV_RESP_STR),QUIT_STR,strlen(QUIT_STR)) == 0) { printf("sender client is existung! "); break; } } } _error1: close(fd); return 0; }

3.3,sever.c

#include "net.h" #include "linklist.h" #include /* IO多路复用select()处理函数 */ void do_select(int fd); int main(int argc, const char *argv[]) { int fd; /* 1 创建socket fd */ if((fd = socket(AF_LOCAL,SOCK_STREAM,0)) < 0)//基于本地的TCP通信 { perror("socket"); exit(-1); } /* 优化 1 允许绑定地址快速重用 */ int b_reuse = 1; setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&b_reuse,sizeof(int)); /* 2.2 绑定*/ /* 2.1 填充struct sockaddr_un 结构体变量*/ struct sockaddr_un sun; bzero(&sun,sizeof(sun)); sun.sun_family = AF_LOCAL; /* 如果UNIX_DOMAun_FILE所指向的文件存在,则删除 */ if(access(UNIX_DOMAIN_FILE,F_OK)) { unlink(UNIX_DOMAIN_FILE);//删除该文件 } strncpy(sun.sun_path,UNIX_DOMAIN_FILE,strlen(UNIX_DOMAIN_FILE)); /* 2.2 绑定*/ if(bind(fd,(struct sockaddr *)&sun,sizeof(sun))) { perror("bind"); goto _error1; } /* 3 使用listen()把主动套接字变成被动套接字 */ if(listen(fd,BACKLOG) < 0) { perror("listen"); goto _error1; } do_select(fd); _error1: close(fd); return 0; } void do_select(int fd) { linklist fdlist,sun_list;//创建一个列表,用于文件描述符及客户端信息存储 fdlist = create_linklist(); datatype sun_data;//每个对象包括客户端的socket fd,ipv4地址,端口号 sun_data.fd = fd; int maxfd = fd; //struct timeval tout = {5,0}; insert_end_linklist(fdlist,sun_data);//将lsten()处理后的fd加入列表 //show_linklist(fdlist); fd_set rset; int newfd = -1; int ret = -1; char buf[BUFSIZ];//BUFSIZ是系统提供的 char resp_buf[BUFSIZ+10]; struct sockaddr_un cun; socklen_t cun_addr_len = sizeof(cun); /* 用select()函数实现I/O多路复用*/ while(1) { int i; FD_ZERO(&rset); if(get_length_linklist(fdlist) >= 1)//将列表中的fd加入读集合进行处理 { //puts("11111111111111111111111111111"); for(i=0;i<get_length_linklist(fdlist);i++) { sun_list = get_list_pos_linklist(fdlist,i); sun_data = sun_list->data; FD_SET(sun_data.fd,&rset); maxfd = sun_data.fd > maxfd ? sun_data.fd : maxfd; //printf("第 %d 个(fd:%d)(ip:%s)(port:%d) ",i,sun_data.fd,sun_data.ipv4_addr,sun_data.port); } //show_linklist(fdlist); } else { continue ; } //switch(select(maxfd+1,&rset,NULL,NULL,&tout)) switch(select(maxfd+1,&rset,NULL,NULL,NULL)) { case 0: { printf("time out! "); goto _error1; } case -1: { perror("select"); goto _error1; } default: { if(FD_ISSET(fd,&rset))//有客户端发送了连接请求 { if((newfd = accept(fd,(struct sockaddr *)&cun,&cun_addr_len)) < 0) { perror("connect"); goto _error1; } /* 将分配成功的套接字newfd设置成非阻塞模式*/ int b_on = 1; ioctl(newfd, FIONBIO, &b_on);//将分配成功的套接字newfd设置为非阻塞方式 sun_data.fd = newfd; printf("get a new client->(ip:%s)(port:%d)(fd:%d) ",sun_data.ipv4_addr,sun_data.port,sun_data.fd); insert_end_linklist(fdlist,sun_data);//将建立客户端连接的fd加入列表 //show_linklist(fdlist); } else//有连接好的客户端发送了数据 { //puts("22222222222222222222"); for(i=0;i<get_length_linklist(fdlist);i++)//将链表中的fd都处理一遍 { sun_list = get_list_pos_linklist(fdlist,i); sun_data = sun_list->data; //printf("readung fd is ->(第 %d 个)(fd:%d)(ip:%s)(port:%d) ",i,sun_data.fd,sun_data.ipv4_addr,sun_data.port); if(sun_data.fd == fd)//不是建立连接后分配的newfd continue ; //puts("########read before"); bzero(buf,BUFSIZ); do { ret = read(sun_data.fd,buf,BUFSIZ-1); }while(ret < 0 && errno == EINTR);//阻塞读写 if(ret < 0) { //perror("read"); continue; } if(ret == 0)//对方已关闭 { printf("client is existung! "); delete_locate_linklist(fdlist,sun_data); continue; } printf("client ip(:%s) port(:%d) fd(:%d) receive data: %s",sun_data.ipv4_addr,sun_data.port,sun_data.fd,buf); bzero(resp_buf,BUFSIZ+25); strncpy(resp_buf,SERV_RESP_STR,strlen(SERV_RESP_STR)); strcat(resp_buf,"ip("); strcat(resp_buf,sun_data.ipv4_addr); char s_port[10]; strcat(resp_buf," port("); sprintf(s_port,"%d",sun_data.port); strcat(resp_buf,s_port); strcat(resp_buf," data("); strcat(resp_buf,buf); do { ret = write(sun_data.fd,resp_buf,strlen(resp_buf)); }while(ret < 0 && EINTR == errno); //puts("###############################"); if(strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)) == 0) { printf("client (fd:%d)(ip:%s)(potr:%d) is existung! ",sun_data.fd,sun_data.ipv4_addr,sun_data.port); delete_locate_linklist(fdlist,sun_data);//将退出的客户端的fd从列表中删除 close(sun_data.fd); //show_linklist(fdlist); } } } } } } close(newfd); _error1: close(fd); clear_linklist(fdlist); }

3.4,linklist.h

#ifndef __SINGLE_LINKLIST_H__ #define __SINGLE_LINKLIST_H__ #include #include #include #include typedef struct{ int fd; char ipv4_addr[16]; int port; }datatype; typedef struct node{ datatype data; struct node *next; }listnode,*linklist; linklist create_linklist(void); linklist create_n_linklist(void); int delete_pos_linklist(linklist L,int pos); int delete_locate_linklist(linklist L,datatype x); void clear_linklist(linklist L); int get_length_linklist(linklist L); linklist get_list_pos_linklist(linklist L,int pos); linklist get_list_locate_linklist(linklist L,datatype x); int insert_head_linklist(linklist L,datatype x); int insert_n_head_linklist(linklist L); int insert_end_linklist(linklist L,datatype x); int insert_n_end_linklist(linklist L); int insert_pos_linklist(linklist L,datatype x,int pos); int insert_order_linklist(linklist L,datatype x); void reverse_linklist(linklist); void sort_linklist(linklist L); void show_linklist(linklist L); #endif

3.5,linklist.c

#include "linklist.h" linklist create_linklist(void) { linklist L; if((L=