linux I/O多路复用 select模型初步代码

发布时间:2024年01月17日

代码来自B站就业班视频

p53课

本文是简单搬运;

目前对老师的代码还有疑惑的地方

为什么文件描述符遍历的时候,是从sfd (监听的描述符) 加1开始。 看很多 博主的文章是从0 开始遍历的

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include<netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>


int main() {
    int sfd = socket(AF_INET, SOCK_STREAM, 0); 
    //设置端口复用,这两行看不懂的跳过去,写不写不影响
    int opt =1;
    setsockopt ( sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
   
    //定义一个地址结gou体
    struct sockaddr_in servad;
    bzero(& servad, sizeof( servad));
    servad.sin_family =AF_INET;
    servad.sin_port =htons(8888);
    servad.sin_addr.s_addr = htonl (INADDR_ANY);
 
    int ret = bind(sfd, (struct sockaddr *)& servad, sizeof( servad));
 
    //将socket从主动变为被动(服务器必备),这样可以监听来自客户的请求
 	listen(sfd,128);  
     //select 模型的相关参数 设置  
     //定义fd_set 类型的变量, 并且清空它们
    fd_set readfds, tmpfds;
    FD_ZERO ( &readfds);
    FD_ZERO ( &tmpfds);
    tmpfds = readfds;
    //把sfd加入到readfds中,让内核监视sfd的变化
    FD_SET (sfd, &readfds);

    int maxfd = sfd;
    int newfd ;
    int i =0;
    int n =0;
    int nready =0;
    int sockfd;

 	while (1) {
        //因为超时时间设置为NULL ,所以进程会无限阻塞在这一步,除非有了变化才往下走
    	nready = select (maxfd+1, &tmpfds, NULL, NULL, NULL);
        if (nready < =0) {
            if (errno ==EINTR ){
                continue;
            }
            break;
        }
        //两种情况,第一种,有新的连接请求。注意,tmpfds  已经变化了,但是readfds没有变化
             if ( FD_ISSET ( sfd, &tmpfds) {
                 newfd = accept (sfd,NULL, NULL);
                 //将newfd纳入内核的监控范围
                 FD_SET ( newfd ,&readfds );  
                 if (maxfd <  newfd) {
                     maxfd = newfd;
                 } 
             }    	
       //第二种情况,目前的文件描述符,有新的内容到了缓冲区了 ..主要是for循环里的东西不懂
       //因为后面i 有变化,所以先定义sockfd = i
       for ( i= sfd+1; i <= maxfd; i++) {
           if ( FD_ISSET ( sockfd, &tmpfds) ){
               char buf[1024];
                //读数据
                memset(buf,0x00,sizeof(buf));
                n =read (sockfd, buf, sizeof(buf));
                if (n < =0){ 
                    printf(“ read error or client close ,n==[%d]\n”, n); 
                    close (sockfd);
                    FD_CLR (sockfd, &tmpfds);
                }
                else {
                    printf (“ 这里是服务器端n =%d ,读到的是%s \n”, n,buf);
                    //将小写字母都转化wie大写
                   for (int j =0; j<n; j++) { 
                       buf[j] =toupper (buf[j]); 
                    }    // ctype.h头文件
                   //发送数据
                   write (sockfd, buf, n);
                }
          }
       }
    }

close (sfd);
return 0;
}

文章来源:https://blog.csdn.net/warmingsummer/article/details/135661073
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。