• l8-d15 IO多路复用select函数


    一、IO多路复用select函数

    1.select函数

    int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
            nfds:         是三个集合中编号最高的文件描述符,加上 1

            readfds/writefds/exceptfds:         可读集合/可写集合/异常集合

            timeout:        NULL: 永久阻塞

                                    0:  非阻塞模式

                            

                            struct timeval {

                                long    tv_sec;         /* 秒 */

                                long    tv_usec;        /* 微秒 */

                            };

    fd_set结构体

    二、多路复用select实现

    服务端

    头文件

    1. #ifndef _NET_H_
    2. #define _NET_H_
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. typedef struct sockaddr Addr;
    13. typedef struct sockaddr_in Addr_in;
    14. #define BACKLOG 5
    15. #define ErrExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while(0)
    16. void Argment(int argc, char *argv[]);
    17. int CreateSocket(char *argv[]);
    18. int DataHandle(int fd);
    19. #endif

    select函数

    1. #include "net.h"
    2. #include
    3. #define MAX_SOCK_FD 1024
    4. int main(int argc, char *argv[])
    5. {
    6. int i, ret, fd, newfd;
    7. fd_set set, tmpset;
    8. Addr_in clientaddr;
    9. socklen_t clientlen = sizeof(Addr_in);
    10. /*检查参数,小于3个 直接退出进程*/
    11. Argment(argc, argv);
    12. /*创建已设置监听模式的套接字*/
    13. fd = CreateSocket(argv);
    14. FD_ZERO(&set);
    15. FD_ZERO(&tmpset);
    16. FD_SET(fd, &set);
    17. while(1){
    18. tmpset = set;
    19. if( (ret = select(MAX_SOCK_FD, &tmpset, NULL, NULL, NULL)) < 0)
    20. ErrExit("select");
    21. if(FD_ISSET(fd, &tmpset) ){
    22. /*接收客户端连接,并生成新的文件描述符*/
    23. if( (newfd = accept(fd, (Addr *)&clientaddr, &clientlen) ) < 0)
    24. perror("accept");
    25. printf("[%s:%d]已建立连接\n",
    26. inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
    27. FD_SET(newfd, &set);
    28. }else{ //处理客户端数据
    29. for(i = fd + 1; i < MAX_SOCK_FD; i++){
    30. if(FD_ISSET(i, &tmpset)){
    31. if( DataHandle(i) <= 0){
    32. if( getpeername(i, (Addr *)&clientaddr, &clientlen) )
    33. perror("getpeername");
    34. printf("[%s:%d]断开连接\n",
    35. inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
    36. FD_CLR(i, &set);
    37. }
    38. }
    39. }
    40. }
    41. }
    42. return 0;
    43. }

    封装函数 

    1. #include "net.h"
    2. void Argment(int argc, char *argv[]){
    3. if(argc < 3){
    4. fprintf(stderr, "%s\n", argv[0]);
    5. exit(0);
    6. }
    7. }
    8. int CreateSocket(char *argv[]){
    9. /*创建套接字*/
    10. int fd = socket(AF_INET, SOCK_STREAM, 0);
    11. if(fd < 0)
    12. ErrExit("socket");
    13. /*允许地址快速重用*/
    14. int flag = 1;
    15. if( setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag) ) )
    16. perror("setsockopt");
    17. /*设置通信结构体*/
    18. Addr_in addr;
    19. bzero(&addr, sizeof(addr) );
    20. addr.sin_family = AF_INET;
    21. addr.sin_port = htons( atoi(argv[2]) );
    22. /*绑定通信结构体*/
    23. if( bind(fd, (Addr *)&addr, sizeof(Addr_in) ) )
    24. ErrExit("bind");
    25. /*设置套接字为监听模式*/
    26. if( listen(fd, BACKLOG) )
    27. ErrExit("listen");
    28. return fd;
    29. }
    30. int DataHandle(int fd){
    31. char buf[BUFSIZ] = {};
    32. Addr_in peeraddr;
    33. socklen_t peerlen = sizeof(Addr_in);
    34. if( getpeername(fd, (Addr *)&peeraddr, &peerlen) )
    35. perror("getpeername");
    36. int ret = recv(fd, buf, BUFSIZ, 0);
    37. if(ret < 0)
    38. perror("recv");
    39. if(ret > 0){
    40. printf("[%s:%d]data: %s\n",
    41. inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port), buf);
    42. }
    43. return ret;
    44. }

  • 相关阅读:
    云原生环境中的自动化测试成功案例分析
    部分准备金银行已经过时
    RabbitMQ学习笔记(一)(概述)
    进程间的通信方式(六种)
    【Python】PySpark 数据处理 ① ( PySpark 简介 | Apache Spark 简介 | Spark 的 Python 语言版本 PySpark | Python 语言场景 )
    JMeter —— 接口自动化测试(数据驱动)
    RSA加密算法
    前端面试手撕编程之ES+算法
    测试人员工作中常用的 git 语句汇总总结
    springboot启动原理最终版
  • 原文地址:https://blog.csdn.net/revengeman/article/details/132890169