使用poll实现的io多路复用服务端和客户端

http://blog.csdn.net/robertkun/article/details/52269313

参考:http://www.cnblogs.com/Anker/p/3261006.html


使用poll实现的io多路复用服务端和客户端。

客户端通过子进程创建多个客户端连接。

客户端每隔1秒向服务端发送一个时间戳,

服务端接收到时间戳以后,保存在本地的文件中,

一个客户端对应一个存储文件,

并将接收到的时间戳返回给客户端。


代码:

服务端:

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4. #include <fcntl.h>  
  5. #include <poll.h>  
  6. #include <errno.h>  
  7. #include <unistd.h>  
  8.   
  9. #include <sys/ioctl.h>  
  10. #include <sys/types.h>  
  11. #include <sys/socket.h>  
  12. #include <sys/stat.h>  
  13.   
  14. #include <netinet/in.h>  
  15. #include <arpa/inet.h>  
  16.   
  17.   
  18. #define IP_ADDR     "127.0.0.1"  
  19. #define PORT        59999  
  20. #define LISTEN_Q    5  
  21. #define OPEN_MAX    100000  
  22. #define INFTIM      -1  
  23. #define MAX_LINE    1024  
  24.   
  25. static int socket_bind(const char* ip, int port);  
  26. static void do_poll(int ln_fd);  
  27. static void handle_conn(struct pollfd* conn_fds, int num, int* files);  
  28.   
  29. int main()  
  30. {  
  31.     int ln_fd, cn_fd, sk_fd = 0;  
  32.     struct sockaddr_in _addr;  
  33.   
  34.     socklen_t _len;  
  35.     ln_fd = socket_bind(IP_ADDR, PORT);  
  36.     listen(ln_fd, LISTEN_Q);  
  37.   
  38.     do_poll(ln_fd);  
  39.     return 0;  
  40. }  
  41.   
  42.   
  43. static int socket_bind(const char* ip, int port)  
  44. {  
  45.     int ln_fd;  
  46.     struct sockaddr_in _addr;  
  47.     ln_fd = socket(AF_INET, SOCK_STREAM, 0);  
  48.     if(ln_fd == -1) {  
  49.         perror("socket error!");  
  50.         exit(1);          
  51.     }  
  52.   
  53.     bzero(&_addr, sizeof(_addr));  
  54.     _addr.sin_family = AF_INET;  
  55.     inet_pton(AF_INET, ip, &_addr.sin_addr);  
  56.     _addr.sin_port = htons(port);  
  57.   
  58.     if(bind(ln_fd, (struct sockaddr*)&_addr, sizeof(_addr)) == -1) {  
  59.         perror("bind error!");  
  60.         exit(1);  
  61.     }  
  62.   
  63.     return ln_fd;  
  64. }  
  65.   
  66. static void do_poll(int ln_fd)  
  67. {  
  68.     int connfd, sockfd = 0;  
  69.     struct sockaddr_in _addr;  
  70.     socklen_t _len;  
  71.     int files[OPEN_MAX];  
  72.     struct pollfd clients[OPEN_MAX];  
  73.     int nMax, i, nReady = 0;  
  74.       
  75.     clients[0].fd = ln_fd;  
  76.     clients[0].events = POLLIN;  
  77.       
  78.     for(i = 1; i<OPEN_MAX; ++i) {  
  79.         clients[i].fd = -1;  
  80.     }  
  81.     nMax = 0;  
  82.   
  83.     while(1) {  
  84.         nReady = poll(clients, nMax+1, INFTIM);  
  85.         if(nReady == -1) {  
  86.             perror("poll error!");  
  87.             exit(1);  
  88.         }  
  89.         else {  
  90.             printf("poll ready num = %d\n", nReady);  
  91.         }  
  92.   
  93.         if(clients[0].revents & POLLIN) {  
  94.             _len = sizeof(_addr);  
  95.             if((connfd = accept(ln_fd, (struct sockaddr*)&_addr, &_len)) == -1) {  
  96.                 if(errno == EINTR) {  
  97.                     printf("EINTR!\n");  
  98.                     continue;  
  99.                 }  
  100.                 else {  
  101.                     perror("accept error!");  
  102.                     exit(1);  
  103.                 }  
  104.             }  
  105.   
  106.             fprintf(stdout, "accept a new client! [%s]\n", inet_ntoa(_addr.sin_addr));  
  107.   
  108.             for(i=1; i<OPEN_MAX; ++i) {  
  109.                 if(clients[i].fd < 0) {  
  110.                     fcntl(connfd, F_SETFL, fcntl(connfd,F_GETFL)| O_NONBLOCK);  
  111.                     unsigned long nVal=1;  
  112.                     ioctl(connfd, FIONBIO, &nVal);  
  113.   
  114.                     clients[i].fd = connfd;  
  115.                     char path[2048] = {"\0"};  
  116.                     getcwd(path, sizeof(path));  
  117.                       
  118.                     sprintf(path, "%s/tmp_%d.txt", path, i);  
  119.                     printf("path=%s\n", path);  
  120.                     int fd = open(path, O_RDWR|O_APPEND|O_CREAT, 0666);  
  121.                     if(fd > 0) {  
  122.                         files[i] = fd;  
  123.                     }  
  124.                     else {  
  125.                         fprintf(stdout, "open file error! [%s]\n", path);  
  126.                         perror("open file error!");  
  127.                     }  
  128.   
  129.                     break;  
  130.                 }  
  131.             }  
  132.   
  133.             fflush(stdout);  
  134.   
  135.             if(i == OPEN_MAX) {  
  136.                 fprintf(stderr, "too many clients\n");  
  137.                 exit(1);  
  138.             }  
  139.   
  140.             clients[i].events = POLLIN;  
  141.             nMax = (i > nMax ? i : nMax);  
  142.             if(--nReady <= 0) {  
  143.                 printf("nReady = %d, nMax = %d\n", nReady, nMax);  
  144.                 continue;  
  145.             }  
  146.         }  
  147.           
  148.         handle_conn(clients, nMax, files);  
  149.     }  
  150. }  
  151.   
  152. static void handle_conn(struct pollfd* conn_fds, int num, int* files)  
  153. {  
  154.     int i, n = 0;  
  155.     char buf[MAX_LINE];  
  156.     memset(buf, 0, MAX_LINE);  
  157.     for(i=1; i<=num; ++i)  
  158.     {  
  159.         if(conn_fds[i].fd < 0)  
  160.             continue;  
  161.   
  162.         if(conn_fds[i].revents & POLLIN) {  
  163.             n = read(conn_fds[i].fd, buf, MAX_LINE);  
  164.             if(n == 0) {  
  165.                 close(conn_fds[i].fd);  
  166.                 conn_fds[i].fd = -1;  
  167.                 continue;  
  168.             }  
  169.   
  170.             write(files[i], buf, n);  
  171.             write(conn_fds[i].fd, buf, n);  
  172.         }  
  173.     }  
  174. }  

客户端:

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4.   
  5. #include <unistd.h>  
  6. #include <sys/types.h>  
  7. #include <sys/socket.h>  
  8.   
  9. #include <netinet/in.h>  
  10. #include <poll.h>  
  11. #include <errno.h>  
  12. #include <arpa/inet.h>  
  13.   
  14. #define MAX_LINE    1024  
  15. #define IP_ADDR     "127.0.0.1"  
  16. #define SERV_PORT   59999  
  17.   
  18. #define max(a,b) (a>b)?a:b  
  19.   
  20. static void do_conn();  
  21. static void handle_conn(int sockfd);  
  22.   
  23. int main(int args, char* argv[])  
  24. {  
  25.     int i = 0;  
  26.     for(i=0; i<2000; ++i) {  
  27.         pid_t fpid = -1;  
  28.         fpid = fork();  
  29.         if(fpid < 0) {  
  30.             printf("error in fork!");  
  31.         }  
  32.         else if(fpid == 0) {  
  33.             do_conn();  
  34.         }  
  35.         else {  
  36.             //do_conn();  
  37.         }  
  38.     }  
  39.   
  40.     return 0;  
  41. }  
  42.   
  43. static void do_conn()  
  44. {  
  45.     int sockfd;  
  46.     struct sockaddr_in _addr;  
  47.     sockfd = socket(AF_INET, SOCK_STREAM, 0);  
  48.   
  49.     bzero(&_addr, sizeof(_addr));  
  50.     _addr.sin_family = AF_INET;  
  51.     _addr.sin_port = htons(SERV_PORT);  
  52.   
  53.     inet_pton(AF_INET, IP_ADDR, &_addr.sin_addr);  
  54.     int ret = connect(sockfd, (struct sockaddr*)&_addr, sizeof(_addr));  
  55.     if(ret < 0) {  
  56.         perror("connect failed!");  
  57.         exit(1);  
  58.     }  
  59.   
  60.     handle_conn(sockfd);  
  61. }  
  62.   
  63. static void handle_conn(int sockfd)  
  64. {  
  65.     char send_line[MAX_LINE] = {'\0'};  
  66.     char recv_line[MAX_LINE] = {'\0'};  
  67.   
  68.     struct pollfd pfds[1];  
  69.     pfds[0].fd = sockfd;  
  70.     pfds[0].events = POLLIN|POLLOUT;  
  71.   
  72.     while(1) {  
  73.         poll(pfds, 1, 1000);  
  74.         if(pfds[0].revents & POLLIN) {  
  75.             int ret = read(sockfd, recv_line, MAX_LINE);  
  76.             if(ret == 0) {  
  77.                 perror("client: server is closed.");  
  78.                 close(sockfd);  
  79.                 continue;  
  80.             }  
  81.             else if(ret < 0) {  
  82.                 perror("client: read error!");  
  83.                 continue;  
  84.             }  
  85.   
  86.             //printf("[%d] recv=%s\n", (int)getpid(), recv_line);  
  87.         }  
  88.   
  89.         if(pfds[0].revents & POLLOUT) {  
  90.             time_t _time = time(0);  
  91.             char dt[20]={"\0"};  
  92.             sprintf(dt, "%d\n", _time);  
  93.   
  94.             memcpy(send_line, dt, strlen(dt));  
  95.             int ret = write(sockfd, send_line, strlen(send_line));  
  96.             if(ret < 0) {  
  97.                 perror("write error!!");  
  98.             }  
  99.         }  
  100.   
  101.         sleep(1);  
  102.     }  
  103.   
  104.     shutdown(sockfd, SHUT_WR);  
  105. }  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383840.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Java学习笔记三】抽象类与接口

对象的类型转换分为自动转换和强制转换两种 派生类向基类转换是自动转换&#xff0c;因为派生类中包含基类基类向派生类的转换是强制转换 强制类型转换是通过在转换对象前面使用圆括号运算符来实现&#xff0c;圆括号内为要转换的目标类型&#xff0c;格式为&#xff1a; (&…

Epoll 的tcp通信代码(服务器+客户端)

http://blog.csdn.net/libinbin_1014/article/details/50096187 Epoll 的tcp通信代码&#xff08;服务器客户端&#xff09; /* gcc -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS64 -I${ORACLE_HOME}/rdbms/public -I${ORACLE_HOME}/rdbms/demo -L${ORACLE_HOME}/lib -lclntsh …

【Java学习笔记四】Java中的包

包的声明和引入&#xff1a;在Java语言系统中&#xff0c;Java编译器为每一个类生成一个字节码文件&#xff08;.class&#xff09;&#xff0c;为了对类文件进行分层和按用途分类管理&#xff0c;同时也为了解决相同类名的文件冲突的问题&#xff0c;Java提供了包机制来管理类…

Linux系统编程——线程池

http://blog.csdn.net/tennysonsky/article/details/46490099# 线程池基本原理 在传统服务器结构中&#xff0c;常是有一个总的监听线程监听有没有新的用户连接服务器&#xff0c;每当有一个新的用户进入&#xff0c;服务器就开启一个新的线程用户处理这 个用户的数据包。这个线…

【Java学习笔记五】Java异常处理

异常通常分为三类&#xff1a; 程序可控制的异常&#xff1a;一般是可预见的错误&#xff0c;不是致命的。例如&#xff1a;除数为0&#xff0c;数组下标越界。程序不可控制的的异常&#xff1a;这种异常往往是致命的&#xff0c;但是系统可以预见的。例如&#xff1a;系统栈溢…

【C++学习笔记一】C++类和对象详解

类定义是以关键字class开头&#xff0c;后面跟类的名称。主体是包含在一对花括号中。类定义后必须跟着一个分号或一个声明列表。 类的对象的公共数据成员可以使用直接成员访问运算符.来访问。需要注意的是&#xff0c;私有的成员和受保护的成员不能直接使用成员访问运算符来访…

C语言实现的简单的线程池

http://www.linuxidc.com/Linux/2013-01/77619.htm 有时我们会需要大量线程来处理一些相互独立的任务&#xff0c;为了避免频繁的申请释放线程所带来的开销&#xff0c;我们可以使用线程池。下面是一个C语言实现的简单的线程池。 头文件&#xff1a; 1: #ifndef THREAD_POOL_H_…

C++获取当前时间

可以使用windowsAPI直接获取。 例如&#xff1a; #include<windows.h> #include<cstdio>using namespace std;int main() {SYSTEMTIME now;GetLocalTime(&now);printf("现在是%02d时%02d分%02d秒\n",now.wHour,now.wMinute,now.wSecond);printf(&…

成员函数后面加上const的作用

const表示成员函数不会修改类中的数据成员。 规则&#xff1a; 在类中被const 声明的函数只能访问const 函数&#xff0c;而非const 函数可以访问任意成员函数。在成员函数中不管数据是否具有const 属性&#xff0c;编译器检查的的是是否有修改&#xff08;赋值&#xff0c;自…

简单Linux C线程池

http://www.cnblogs.com/venow/archive/2012/11/22/2779667.html 大多数的网络服务器&#xff0c;包括Web服务器都具有一个特点&#xff0c;就是单位时间内必须处理数目巨大的连接请求&#xff0c;但是处理时间却是比较短的。在传统的多线程服务器模型中是这样实现的&#xff1…

C++创建对象:栈和堆的区别

首先我们应该了解栈和堆的差别&#xff1a; 详细信息&#xff1a;传送门 栈相当于函数自带的存储空间&#xff0c;在windows下一般为2M,在Linux下一般为8M&#xff0c;存取速度稍微快一点。堆是系统的空间&#xff0c;相对较大&#xff0c;一般为2G&#xff0c;效率稍微慢一点…

IO多路复用之poll总结

http://www.cnblogs.com/Anker/p/3261006.html 1、基本知识 poll的机制与select类似&#xff0c;与select在本质上没有多大差别&#xff0c;管理多个描述符也是进行轮询&#xff0c;根据描述符的状态进行处理&#xff0c;但是poll没有最大文件描述符数量的限制。poll和select同…

【C++学习笔记二】C++继承

继承 继承允许我们一句另一个类来定义一个类&#xff0c;这使得继承和维护一个程序变得更加容易&#xff0c;也达到了重用代码功能和提高执行效率的效果。 一般格式为&#xff1a; class 派生类名 :访问修饰符 基类名{};其中访问修饰符是public protected private中的一个&a…

处理大并发之二 对epoll的理解,epoll客户端服务端代码

http://blog.csdn.net/wzjking0929/article/details/51838370 序言&#xff1a; 该博客是一系列的博客&#xff0c;首先从最基础的epoll说起&#xff0c;然后研究libevent源码及使用方法&#xff0c;最后研究nginx和node.js&#xff0c;关于select,poll这里不做说明&#xff0c…

C++基类指针指向派生类(指针)

我们常用基类指针指向派生类对象来实现多态性。 私有继承不允许基类指针指向派生类 基类指针只能访问到基类中含有的公有成员。 当用基类指针指向派生类对象在动态分配堆上内存的时候&#xff0c;析构函数必须是虚函数! 成员如果是数据成员的话访问的是基类的版本&#xff…

C++虚继承中构造函数和析构函数顺序问题以及原理

多重继承的问题&#xff1a;多个类B,C,…继承同一个类A导致如果X继承了B,C,…那么在X中将还有多个A中成员的拷贝&#xff0c;如果想要访问A中的成员如果不加名字空间将会导致二义性&#xff0c;这种拷贝大多是没有实际意义的&#xff0c;为了避免这种空间浪费&#xff0c;C有虚…

一个简单的linux线程池

http://blog.csdn.net/wzjking0929/article/details/20312675 线程池&#xff1a;简单地说&#xff0c;线程池 就是预先创建好一批线程&#xff0c;方便、快速地处理收到的业务。比起传统的到来一个任务&#xff0c;即时创建一个线程来处理&#xff0c;节省了线程的创建和回收的…

【C++学习笔记三】C++多态、抽象(接口)

当类之间存在多种层次结构&#xff0c;并且类之间通过继承关联时就会用到多态。 虚函数在子类中的覆盖版本和该函数在基类中的原始版本必须有相同的函数签名、函数名、形参名、常属性。如果返回值为非类类型&#xff0c;则必须相同&#xff0c;如果是类类型A的指针或者引用&am…

C++重载和重写的条件以及重写后对基类函数的覆盖

重载&#xff1a;同一个类中名字相同&#xff0c;参数列表不同的方法构成重载函数&#xff0c;和返回值没有关系。这就意味着就算返回值不同&#xff0c;只要名字相同参数列表相同编译器还是会报错&#xff0c;觉得一函数被定义了两次。 重写&#xff1a;派生类中只要函数名字…

C++静态成员和静态方法

在类中&#xff0c;静态成员可以实现多个对象之间共享数据&#xff0c;同时保证了安全性。静态数据对该类的所有对象是公有的&#xff0c;存储一处供所有对象使用。 注意&#xff1a; 静态成员定义时需要在前面加上关键字static静态成员必须初始化且必须在类外进行&#xff0…