Linux 嵌入式开发 网络编程: day4

【1】IO多路复用  (并发服务器)
    想实现服务器处理多个客户端连接请求或数据收发的话,(实现并发)
    1. 多进程的方式;
    2. 多线程的方式;
    3. IO多路复用
         a. select
            弊端: 1. 一个进程最多只能监听1024个文件描述符 (千级别)
                    2. select是一种轮询的机制;
                    3. 涉及到用户态和内核态的数据拷贝;
        
         b. poll
                    1. 优化文件描述符个数的限制;
                    2. poll是一种轮询的机制;
                    3. 涉及到用户态和内核态的数据拷贝;
                   
             int poll( struct pollfd *fds, nfds_t nfds, int timeout );
                    基本思想:同select;
            参数:
                 struct pollfd *fds
                关心的文件描述符数组struct pollfd fds[N];
                 nfds:个数
                 timeout: 超时检测
                                 毫秒级的:如果填1000就是1秒
                                                  如果填-1,阻塞
                                  
            问题:
            我想检测是键盘事件(标准输入 文件描述如为0 ),
            还是鼠标事件(文件描述符是/dev/input/mouse1);                  
                
            1. 创建一个结构体数组
                struct pollfd fds[2];
            2. 将你关心的文件描述符加入到结构体成员中
                struct pollfd {
                   int   fd;         // 关心的文件描述符;
                   short events;     // 关心的事件,读
                   short revents;    // 如果产生事件,则会自动填充该成员的值
                };
            
                // 键盘
                fds[0].fd = 0;
                fds[0].events = POLLIN;
                
                //鼠标
                fds[1].fd = mouse1_fd;
                fds[1].events = POLLIN;
            
            3. 调用poll函数
                如果返回表示有事件产生;
                poll(fds,2,1000)
            4. 判断具体是哪个文件描述符产生了事件
                if(fds[0].revents == POLLIN)
                {
                    ....
                }
            
         c. epoll
             1. 没有文件描述符的限制
             2. 异步IO,当有事件产生,文件描述符主动调用callback(每一个文件描                                                                                       述符都有自己的callback)
             3. 不用数据拷贝;
            
        3个功能函数:
            #include <sys/epoll.h>
             int epoll_create(int size);//创建红黑树根节点
            //成功时返回epoll文件描述符,失败时返回-1
            
            //控制epoll属性
             int epoll_ctl( int epfd , int op , int fd , struct epoll_event *event );
            epfd:epoll_create函数的返回句柄。
            op:表示动作类型。有三个宏 来表示:
            EPOLL_CTL_ADD:注册新的fd到epfd中
            EPOLL_CTL_MOD:修改已注册fd的监听事件
            EPOLL_CTL_DEL:从epfd中删除一个fd
            FD:需要监听的fd。
            event:告诉内核需要监听什么事件
                EPOLLIN:表示对应文件描述符可读
                EPOLLOUT:可写
                EPOLLPRI:有紧急数据可读;
                EPOLLERR:错误;
                EPOLLHUP:被挂断;
                EPOLLET:触发方式,电平触发;
                     ET模式:表示状态的变化;
            //成功时返回0,失败时返回-1
            
            //等待事件到来
             int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
            功能:等待事件的产生,类似于select的用法
            epfd:句柄;
            events:用来从内核得到事件的集合;
            maxevents:表示每次能处理事件最大个数;
            timeout:超时时间,毫秒,0立即返回,-1阻塞
            
            //成功时返回发生事件的文件描述数,失败时返回-1
【2】服务器模型
    1、循环服务器:
        依次只能处理一个客户端,等这个客户端所有请求都完成后(客户端关闭),
        才能处理下一个客户端
        
        缺点: 循环服务器所处理的客户端,不能做耗时动作
        
        socket(...);
        bind(...);
        listen(...);
        while(1)
        {    
            accept(...);
            while(1)
            {          
                recv(...);
                process(...);
                send(...);
            }     
            close(...);
        }
    2、并发服务器:
        可以同时处理多个客户端的请求,创建子进程/子线程来处理跟客户端的请求
        流程如下:
        void handler(int sigo)
        {
            while (waitpid(-1, NULL, WNOHANG) > 0);     //一个SIGCHLD可能对应多个僵尸进程,循环收尸
        }
        int sockfd = socket(...);
        bind(...);
        listen(...);
        signal(SIGCHLD, handler);  //注册SIGCHLD信号,当产生SIGCHLD信号时调用handler函数
        while(1) {
            int connfd = accept(...);
            if (fork() == 0) {
                close(sockfd);
                while(1)
                {
                    recv(...);
                    process(...);
                    send(...);
                }
                close(connfd);           
                exit(...);
            }
            close(connfd);
        }
        效果: 父进程--只做链接    子进程--跟客户端的通信(耗时)            
            
【3】    wireshark 抓包工具
        windows版本或ubuntu版本
        
        1. 安装
        sudo apt-get install wireshark
        2. 运行
            sudo wireshark
        3. 过滤
            tcp.port == 8888
        4. 抓的是流经eth0网卡的数据
            服务器端代码运行在ubuntu
            客户端代码运行在windows下
            
        ip.addr == 192.168.1.31
【4】三次握手和四次挥手
    
    ACK: 确认包;握手
    SYN:  同步包;握手
    FIN: 结束包;挥手    
                        
三次握手:
    在建立连接的时候进行。客户端主动方,连接服务器;
    第一次握手(connect),有客户端向服务器发送SYN同步包,告诉服务器我要连接了
    第二次握手,服务器收到SYN后,要回复一个确认包,告诉客户端已经收到了,
                并发送同步包(确认一下服务器发的包是否能发出去);
    第三次握手,客户端发送确认包给服务器;
    
四次挥手:
    TCP套接字是全双工的;close时,两端都要关闭
    客户端和服务器都可以作为主动方;
    
    第一次挥手;客户端调用close,发送FIN包;
    第二、三次挥手;服务器端,先回复确认包,确认已经收到断开连接的请求,
            并且再发FIN结束包;
    第四次挥手;客户端再次发送ACK确认包;        
            
【5】网络信息检索和套接字属性设置
        
    getsockopt()/setsockopt() 获取/设置一个套接口选项
    
    bind failed.: Address already in use
    
        #include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>
    int getsockopt(int sockfd, int level, int optname,
                    void *optval, socklen_t *optlen);
                      
                      
    int setsockopt(int sockfd, int level, int optname,
                      const void *optval, socklen_t optlen);
    功能:设置套接字选项
    参数:    
        sockfd:套接字
        level: 层次  
                SOL_SOCKET  应用层
                IPPROTO_IP  IP层/网络层
                IPPRO_TCP  传输层
        optname:  具体值
                    SO_REUSEADDR
        optval:值 (有对应的类型)
                重用本地地址和端口        
                允许或不允许
        optlen:
                大小
        
        允许地址端口重用,代码如下:
        int optval = 1;
        socklen_t optval_len = sizeof(optval);
        setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&optval,optval_len);
        
        
        
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值