• server.c客户端服务器select 赵超越


    班级:09计算机用技术1班     姓名:赵超越      学号:0906041011

     

    /* server.c */
    #include
    #include
    #include
    #include
    #include "wrap.h"

    #define MAXLINE 80
                     /*宏定义 MAXLINE 为 80*/
    #define SERV_PORT 8000
               /*宏定义 端口号为 8000*/

    int main(int argc, char **argv)
    {
        int i, maxi, maxfd, listenfd, connfd, sockfd;
        int nready, client[FD_SETSIZE];
        ssize_t n;
        fd_set rset, allset;
                                      /*定义fd_set(文件描述符的集合)型变量 rset allset*/
        char buf[MAXLINE];
                                   /*定义缓冲区数组buf[ ]*/
        char str[INET_ADDRSTRLEN];
                    /*定义字符数组str[ ]*/
        socklen_t cliaddr_len;
        struct sockaddr_in    cliaddr, servaddr;

        listenfd = Socket(AF_INET, SOCK_STREAM, 0);
          /*打开一个网络通讯端口,地址类型IPV4,TCP协议*/


        bzero(&servaddr, sizeof(servaddr));
                            /*servaddr 初始化*/
        servaddr.sin_family      = AF_INET;
                            /*设置地址类型为 IPV4*/
        servaddr.sin_a
    ddr.s_addr = htonl(INADDR_ANY);         /*设置网络地址为本地任意IP地址*/

    servaddr.sin_port = htons(SERV_PORT); /*定义端口号 SERV_PORT(8000)*/
       

     Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));                                /*调用bind将参数listenfd与servaddr绑定,使listenfd监听servaddr所描述的地址和端口*/

        Listen(listenfd, 20);
         /*listen()声明listenfd处于监听状态,并且最多允许有backlog个客户端处于连接待状态,0—成功,-1—失败*/

        maxfd = listenfd;        /
    *将maxfd初始化*/
        maxi = -1;           
       /*将maxi赋初值为-1*/
        for (i = 0; i < FD_SETSIZE; i+
    +)
            client[i] = -1;   
                              /*将client[i]中的每一个元素赋初值为-1*/
        FD_ZERO(&allset);
                /* 将文件描述符集合allset*/
        FD_SET(listenfd, &allset);
         /*将监听文件描述符listenfd放入集合allset中*/

        for ( ; ; )
    {            /*死循环*/
            rset = allset;   
            nready = select(maxf
    d+1, &rset, NULL, NULL, NULL);/* 调用select函数它可以同时监听多个阻塞的文件描述符,并且处理有数据到达的文件描述符,并返回更新的个数给nready,没有数据到达就阻塞*/
            if (nready < 0)
                perr_exit("select error");
         /*当nready小于0时出错* /

            if (FD_ISSET(listenfd, &rset)) {
    /*检测文件描述符listenfd是否在rset集合(检测rset中是否有新的连接出现/*
               
    cliaddr_len = sizeof(cliaddr); /*cliaddr_len赋初值,并将本地客户端地址的长度放入变量cliaddr_len中*/
             
    connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);  /*服务器调用accept()接受连接,若没有客户端的连接请求,就阻塞等待直到有客户端连接上来;若有客户端连接则解除阻塞状态,并返回一个服务器与客户端互相通信的文件描述符connfd*/

                printf("received from %s at PORT %d ",
                       inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
               
           ntohs(cliaddr.sin_port)); /*打印连接的客户端地址和端口号*/

                for (i = 0; i < FD_SETSIZE; i++)
                    if (client[i] < 0) {
                        client[i] = connfd;
    /*将已连接到服务器的客户端的文件描述符放入数组client[i]中*/
                        break;
                 
      }
                if (i == FD_SETSIZE) {
                    fputs("too many clients ", stderr);/
    *如果i == FD_SETSIZE表示连接已满,输出错误信息" too many clients "*/
                    exit(1);
         /*异常退出*/
                }

                FD_SET(connfd, &allset);
    /*将新的文件描述符connfdt添加到allset中 */
                if (connfd > maxfd)
                    maxfd = connfd;
    /*如果connfd > maxfd,则将connfd的值赋给maxfd使maxfd存放的是最大的文件描述符*/
                if (i > maxi)
                    maxi = i;   
    /*如果i > maxi,将i的值赋给maxi使得maxi存放的是值最大的i*/

                if (--nready == 0)

                    continue;                                    /*当nready为0,没有可读的文件描述符,结束本次循环。并开始执行下一次循环*/

            }

            for (i = 0; i <= maxi; i++) {   
                    /* check all clients for data */
                if ( (sockfd = client[i]) < 0)
                    continue;
                                            /*如果没有连接,结束本次循环,并开始执行下一次循环*/
                if (FD_ISSET(sockfd, &rset))
            /*检测文件描述符listenfd是否在rset集中*/

    {
                 
    if ( (n = Read(sockfd, buf, MAXLINE)) == 0)                 /*判断客户端连接是否关闭*/

    {                           
                        Close(sockfd);
                                            /*如果客户端连接关闭,服务器端连接关闭*/
                        FD_CLR(sockfd, &allset);
                    /*sockfd将文件描述符从allset中清除*/
                        client[i] = -1;
                    } else {
                                    /*若客户端连接没有关闭*/
                        int j;
                        for (j = 0; j < n; j++)
                            buf[j] = toupper(buf[j]);
                    /*将buf[j]中的小写字母全部转换为大写字母,并存入buf[j]中*/
                        Write(sockfd, buf, n);
                      /*调用write将处理结果发给客户端*/
                    }

                    if (--nready == 0)
                        break;    /
    *当nready为0,没有可读的文件描述符,结束本次循环*/
                }
            }
        }
    }
    执行过程:

    首先系统调用socekt返回一个文件描述符listenfd监听SERV_PORT端口。然后调用bind将listenfd 和服务器地址servaddr 绑定在一起,使listenfd这个用于网络通讯的文件描述符监听servaddr 所描述的地址(本地任意IP地址)和端口号(8000)服务器调用listen()声明sockfd处于监听状态,并且最多允许有20个客户端处于连接待状态,如果接收到更多的连接请求就忽略。

    然后把listenfd加入allset集合中调 用select()函数判断rset 中存放的listenfd 是否有数据到达,现在有一个文件描述符listenfd 在rset 中,假设有数据到达返回1赋给nready , 判断 nready 不小于0,所以不出错。接着服务器调用accept()接受连接,如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接 上来。当集合里有可读的socket时,select返回。select返回后,判断是否是listenfd可读,如果为真,则说明有新的客户端连接进来,然后调用accept函数进行接收accept()返回时返回一个服务器与客户端互相通信的文件描述符connfd,存放传出客户端的地址和端口号并打印Accept到的connfd保存到客户端列表里(client[i] 数组中的第一个位置), 通过if 语句判断i 不等于FD_SETSIZE退出。把最大的描述符添加到allset集中,把最大的i 值赋给maxi , nready = 1继续返回执行for循环,重新等待监听来自客户端的连接请求。 把client[i] 中第一个元素(即第一个文件描述符listenfd )赋给sockfd 不小于0执行下面的if 语句,判断sockfd(listenfd )在rset 集中,接着判断客户端是否关闭连接若已经关闭连接,将sockfd(listenfd )从allset 集中清除,将client[i]的第一个元素赋值为-1若没有关闭连接,将接收到的来自客户端的数据由小写转换为大写,重新返回给客户端果客户端断开,那么从client列表和集合里去除掉。连接关闭后,此时nready = 1执行“——”操作后后等于0没有更多的文件描述符,结束本次循环,进入下一次for循环,重新监听来自客户端的连接请求。

     

    执行结果:

    终端1:

    [root@localhost ~]#cd /opt/zcy/

    [root@localhost zcy]#gcc server.c -o server

    [root@localhost zcy]#./server

    received from 127.0.0.1 at PORT 50275

    received from 127.0.0.1 at PORT 50276

    终端2:

    [root@localhost zcy]# ./client

    zcy

    ZCY

    nypd

    NYPD

    www

    WWW

    终端3:

    [root@localhost ~]# cd /opt/zcy/

    [root@localhost zcy]# ./client

    zhongduan3

    ZHONGDUAN3

     

     

     

    <script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
    阅读(336) | 评论(0) | 转发(0) |
    给主人留下些什么吧!~~
    评论热议
  • 相关阅读:
    球员岁月齐祖辉煌,执教生涯尤胜当年
    UVM序列篇之一:新手上路
    *2-3-7-加入field_automation机制
    2.3.6-加入scoreboard
    *2_3_5_加入reference model
    *2.3.4_封装成agent
    *2.3.3-加入monitor
    android的wake_lock介绍
    linux常用命令一些解释
    linux wc命令的作用。
  • 原文地址:https://www.cnblogs.com/ztguang/p/12647581.html
Copyright © 2020-2023  润新知