嵌入式Linux网络编程,I/O多路复用,select()示例,select()客户端,select

2019-07-12 18:47发布

文章目录

1,IO复用select()示例

1.1 select()—net.h

#ifndef __NET_H__ #define __NET_H__ #include #include #include #include #include #include #include #include #include #include #include #define SERV_IP_ADDR "192.168.31.100" #define SERV_PORT 5002 #define BACKLOG 5 #define QUIT_STR "quite" #define SERV_RESP_STR "Server:" #endif

1.2 select()—client.c

/* ./client serv_ip serv_port */ #include "net.h" void usage(char *s) { printf("Usage: %s ",s); printf(" serv_ip: server ip address "); printf(" serv_port: server port(>5000) "); } int main(int argc, const char *argv[]) { int fd; short port; struct sockaddr_in sin; if(argc != 3) { usage((char *)argv[0]); exit(1); } if((port = atoi(argv[2])) < 5000) { usage((char *)argv[0]); exit(1); } /* 1 创建socket fd */ if((fd = socket(AF_INET,SOCK_STREAM,0)) < 0) { perror("socket"); exit(-1); } /* 2 连接服务器 */ /* 2.1 填充struct sockaddr_in结构体变量*/ bzero(&sin,sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(port);//转为网络字节序端口号 if(inet_pton(AF_INET,argv[1],(void *)&sin.sin_addr.s_addr) < 0) { perror("inet_pton"); goto _error1; } /* 2.2 连接服务器*/ if(connect(fd,(struct sockaddr *)&sin,sizeof(sin)) < 0) { perror("connect"); goto _error1; } printf("client staring ... 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 existing! "); 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 existing! "); break; } } } _error1: close(fd); return 0; }

1.3 select()—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; struct sockaddr_in sin;//如果是IPV6的编程,要使用struct sockddr_in6结构体(详细情况请参考man 7 ipv6),通常更通用的方法可以通过struct sockaddr_storage来编程 /* 1 创建socket fd */ if((fd = socket(AF_INET,SOCK_STREAM,0)) < 0) { perror("socket"); exit(-1); } /* 优化 1 允许绑定地址快速重用 */ int b_reuse = 1; setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&b_reuse,sizeof(int)); /* 2 绑定 */ /* 2.1 填充struct sockaddr_in 结构体变量*/ bzero(&sin,sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(SERV_PORT); #if 1 /* 优化 2 让服务器可以绑定在任意的IP上*/ sin.sin_addr.s_addr = htonl(INADDR_ANY); #else if(inet_pton(AF_INET,SERV_IP_ADDR,(void *)&sin.sin_addr.s_addr) < 0) { perror("inet_pton"); goto _error1; } #endif /* 2.2 绑定*/ if(bind(fd,(struct sockaddr *)&sin,sizeof(sin))) { 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,sin_list;//创建一个列表,用于文件描述符及客户端信息存储 fdlist = create_linklist(); datatype sin_data;//每个对象包括客户端的socket fd,ipv4地址,端口号 sin_data.fd = fd; int maxfd = fd; //struct timeval tout = {5,0}; insert_end_linklist(fdlist,sin_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_in cin; socklen_t cin_addr_len = sizeof(cin); /* 用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++) { sin_list = get_list_pos_linklist(fdlist,i); sin_data = sin_list->data; FD_SET(sin_data.fd,&rset); maxfd = sin_data.fd > maxfd ? sin_data.fd : maxfd; //printf("第 %d 个(fd:%d)(ip:%s)(port:%d) ",i,sin_data.fd,sin_data.ipv4_addr,sin_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 *)&cin,&cin_addr_len)) < 0) { perror("connect"); goto _error1; } /* 将分配成功的套接字newfd设置成非阻塞模式*/ int b_on = 1; ioctl(newfd, FIONBIO, &b_on);//将分配成功的套接字newfd设置为非阻塞方式 sin_data.fd = newfd; if(inet_ntop(AF_INET,&cin.sin_addr.s_addr,sin_data.ipv4_addr,sizeof(sin_data.ipv4_addr)) < 0) { perror("inet_ntop"); goto _error2; } sin_data.port = ntohs(cin.sin_port); printf("get a new client->(ip:%s)(port:%d)(fd:%d) ",sin_data.ipv4_addr,sin_data.port,sin_data.fd); insert_end_linklist(fdlist,sin_data);//将建立客户端连接的fd加入列表 //show_linklist(fdlist); } else//有连接好的客户端发送了数据 { //puts("22222222222222222222"); for(i=0;i<get_length_linklist(fdlist);i++)//将链表中的fd都处理一遍 { sin_list = get_list_pos_linklist(fdlist,i); sin_data = sin_list->data; //printf("reading fd is ->(第 %d 个)(fd:%d)(ip:%s)(port:%d) ",i,sin_data.fd,sin_data.ipv4_addr,sin_data.port); if(sin_data.fd == fd)//不是建立连接后分配的newfd continue ; //puts("########read before"); bzero(buf,BUFSIZ); do { ret = read(sin_data.fd,buf,BUFSIZ-1); }while(ret < 0 && errno == EINTR);//阻塞读写 if(ret < 0) { //perror("read"); continue; } if(ret == 0)//对方已关闭 { printf("client is existing! "); delete_locate_linklist(fdlist,sin_data); continue; } printf("client ip(:%s) port(:%d) fd(:%d) receive data: %s",sin_data.ipv4_addr,sin_data.port,sin_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,sin_data.ipv4_addr); char s_port[10]; strcat(resp_buf," port("); sprintf(s_port,"%d",sin_data.port); strcat(resp_buf,s_port); strcat(resp_buf," data("); strcat(resp_buf,buf); do { ret = write(sin_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 existing! ",sin_data.fd,sin_data.ipv4_addr,sin_data.port); delete_locate_linklist(fdlist,sin_data);//将退出的客户端的fd从列表中删除 close(sin_data.fd); //show_linklist(fdlist); } } } } } } _error2: close(newfd); _error1: close(fd); clear_linklist(fdlist); }

1.4 select()—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

1.5 select()—linklist.c

#include "linklist.h" linklist create_linklist(void) { linklist L; if((L=(linklist)malloc(sizeof(listnode))) == NULL)