zoukankan      html  css  js  c++  java
  • Linux网络编程--tinyhttpd

    CRLF:回车换行(Carriage-Return Line-Feed)。
    CR:回车,ASCII 0x0d,转义字符 ,
    LF:换行,ASCII 0x0a,转义字符 。
    windows下使用 换行,linux使用 换行。
    在wireshark抓包中看到,不管是服务器还是客户端,HTTP协议中的换行是0x0d 0x0a,空格是0x20

    //客户端步骤
    socket()
    connect()//阻塞
    write()
    read()
    
    //服务端步骤
    socket()
    bind()
    listen()
    accept()//阻塞
    read()
    write()

    echo服务器重点语句

    //客户端
    connect()//阻塞
    while(fget()) {
        write();
        if(readline()==0)
            error();
        fpus();
    }
    
    //服务端
    listen(sockfd, 1);//listen
    
    while(1) {
       if((connfd = accept(sockfd, (struct sockaddr*)&cliaddr, &clilen)) < 0) {//阻塞
           if(errno == EINTR) {
               printf("accept EINTR
    ");
               continue;
           }
           else
               perror("accept error
    ");
       }
       if((childpid = fork()) == 0) {//进程
           printf("It's child.
    ");
           close(sockfd);
           str_echo(connfd);
           exit(0);
       }
       close(connfd);
    }

    引入IO复用

    在上述的服务器和客户端实际运行的过程中,当客户端阻塞在fgets,我们终止服务器程序。这时的客户端还是阻塞在fgets,用户不知道服务器那边发生了什么。为了让服务器关闭时,客户端也相应地关闭,我们需要使用IO复用。
    在服务器方面,使用select可以将上述例子由多进程改为单进程,减少创建新进程的开销。

    select函数

    select函数的参数是值-结果类型
    跟select函数一起使用的还有:
    FD_SET
    FD_ZERO
    FD_ISSET

    //使用select的客户端
    FD_ZERO(&rset);//复位描述字集
    while(1) {
        FD_SET(fileno(fp), &rset);//置位感兴趣的描述字,一个是标准输入,一个是socket
        FD_SET(sockfd, &rset);
        maxfdp1 = max(fileno(fp), sockfd) + 1;
        select(maxfdp1, &rset, NULL, NULL, NULL);//阻塞。若描述字集里有就绪好的描述字,就往下执行
    
        if(FD_ISSET(sockfd, &rset)) {//sockfd是否就绪好,若服务器突然关闭,则sockfd会就绪好
            if(readline(sockfd, recvline, MAXLINE) == 0) {
                exit(1);
            }
            fputs(recvline, stdout);
        }
    
        if(FD_ISSET(fileno(fp), &rset)) {//fp是否就绪好
            if(fgets(sendline, MAXLINE, fp) == NULL)
                return;
            writen(sockfd, sendline, strlen(sendline));
        }
    }
    
    //使用select的单进程服务器
    fd_set rset;
    int client[FD_MAX];//客户端描述字集
    FD_ZERO();
    FD_SET(linstenfd);
    while(1) {
        select(&rset);//阻塞,当客户与服务器建立连接时,监听描述字就绪
        if(FD_ISSET(linstenfd)) {//有新的客户连接进来
            connfd = accept();
            FD_SET(connfd);//把连接描述字加入感兴趣集
        }
        for() {//遍历客户描述字集client,找出非负描述字,即目前保持连接状态的客户
            if(FD_SET(&rset)){//该客户是否就绪可以读取内容了
                read();
                write();
            }
        }
    }

    poll函数

    poll函数的参数不同于select的值-结果类型,poll既有输入参数,也有输出参数。
    select需要维护一个client[]数组和select函数所需要的描述字集fd_set,而poll只需要维护一个结构体数组pollfd即可。

    //使用poll的单进程服务器
    struct pollfd client[FD_MAX];//客户端描述字集
    client[0].fd = linstenfd;
    client[0].events = POLLRDNORM;
    while(1) {
        poll(client);//阻塞,当客户与服务器建立连接时,监听描述字就绪
        if(client[0].revents & POLLRDNORM) {//有新的客户连接进来
            connfd = accept();
            client[0].fd = connfd;//把连接描述字加入感兴趣集
            client[0].events = POLLRDNORM;//设置感兴趣的事件
        }
        for() {//遍历客户描述字集client,找出非负描述字,即目前保持连接状态的客户
            if(client[i].revents & (POLLRDNORM | POLLRDERR){//该客户是否就绪可以读取内容了
                read();
                write();
            }
        }
    }
  • 相关阅读:
    【分布式事务】的一篇良心之作!
    如何保证缓存与数据库的数据一致性
    30多岁的大龄程序员,应该如何保持职场竞争力
    Kafka acks参数对消息持久化的影响
    Kafka 如何优化内存缓冲机制造成的频繁 GC 问题?
    Shell中的特殊符号(special characters)和含义
    Bash中的一些常用的数组相关的特殊语法(array syntax)
    一站式搞定Bash脚本的参数处理问题
    Bash脚本set命令教程
    Bash中的eval命令
  • 原文地址:https://www.cnblogs.com/season-peng/p/6759522.html
Copyright © 2011-2022 走看看