zoukankan      html  css  js  c++  java
  • select注释执行过程 刘峰

    09嵌入式方向    计应(2)班        刘峰


    select注释执行过程

    /* server.c */

    #include

    #include

    #include

    #include

    #include "wrap.h"   /* wrap.c头文件*/

    #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];//nready 存放有数据请求的个数,client[FD_SETSIZE]存放数据请求客户端的最大连接数为FD_SETSIZE(1024)

            ssize_t n; //定义一个有符号size_t变量n

            fd_set rset, allset;

            char buf[MAXLINE];

            char str[INET_ADDRSTRLEN];

            socklen_t cliaddr_len;

            struct sockaddr_in        cliaddr, servaddr;//定义两个结构体

             listenfd = Socket(AF_INET, SOCK_STREAM, 0);//打开一个网络通信端口地址类型IPV4,通信类型TCP,并且将值赋给文件描述符变量listenfd

            bzero(&servaddr, sizeof(servaddr));//将服务器结构体清零

            servaddr.sin_family      = AF_INET;//服务器地址类型ipv4

            servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//ip地址为本地的任意IP地址,可以在所有IP地址上监听

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

            Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));//服务端调用bind邦定端口号和服务器地址

            Listen(listenfd, 20);//监听网路通讯端口最到允许20个客户端接入

            maxfd = listenfd;                /* 将tcp连接端口初始化赋值给maxfd */

            maxi = -1;                        /* 初始化客户端 */

            for (i = 0; i < FD_SETSIZE; i++)

                    client[i] = -1;        /* 初始化连接空间 */

            FD_ZERO(&allset);//将&allset端口集清零

            FD_SET(listenfd, &allset);//将listenfd文件描述符添加到&allset描述符集中

            for ( ; ; ) {

                    rset = allset;        /* 把存在allset中的文件描述符中的值赋rset */

                    nready = select(maxfd+1, &rset, NULL, NULL, NULL);//保存连接描述符到nready中

                    if (nready < 0)//判断select是否成功失败返回"select error"

                            perr_exit("select error");

                    if (FD_ISSET(listenfd, &rset)) { /* 创建新的客户端连接将值放入 &rset中*/

                            cliaddr_len = sizeof(cliaddr);//得到客户端缓冲区长度

                            connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);//服务器接受客户端连接请求传出客户端地址传入缓冲区长度

                            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++) //循环i的值要小于客户端的最大连接数

                                    if (client[i] < 0) {

                                            client[i] = connfd; /* 如果请求连接个数小于零将已有的连接客户端文件描述保存在client数组中 */

                                            break;

                                    }

                            if (i == FD_SETSIZE) {

                                    fputs("too many clients ", stderr);

                                    exit(1);//如果i的值已经达到连接的最大上限输出错误“超过连接客户端的总数”

                            }

                            FD_SET(connfd, &allset);        /* 将新文件描述符添加到&allset中 */

                            if (connfd > maxfd)

                                    maxfd = connfd; /* 若连接的客户端大于请求客户端将连接客户端赋值给 maxfd*/

                            if (i > maxi)

                                    maxi = i;        /* 若已有的连接客户端总个数大于已连接的客户端数,则会为已连接的客户端创建索引 */

                            if (--nready == 0)

                                    continue;        /* 没有客户端数据请求进行下一轮 select*/

                    }

                    for (i = 0; i <= maxi; i++) {        /* 检查所有请求端口的个数 */

                            if ( (sockfd = client[i]) < 0)//把 client[i]文件描述符赋值给sockfd如果小于0则没有请求客户端

                                    continue;

                            if (FD_ISSET(sockfd, &rset)) {//判断sockfd文件描述符是否在&rset文件描述符集中

                                    if ( (n = Read(sockfd, buf, MAXLINE)) == 0) {//读出客户端数据是否为0

                                            /* connection closed by client */

                                            Close(sockfd);//关闭通信端口

                                            FD_CLR(sockfd, &allset);//从&allset中清除文件描述符数据

                                            client[i] = -1; //n不为零表示有客户端数据请求

                                    } else {

                                            int j;

                                            for (j = 0; j < n; j++)

                                                    buf[j] = toupper(buf[j]);//把buf客户端的数据请求转化为大写

                                            Write(sockfd, buf, n);//将转化后数据发给客户端

                                    }

                                    if (--nready == 0)//无数据写入请求则结束循环

                                            break;        /* no more readable descriptors */

                            }

                    }

            }

    }

    总结:此程序是用select实现服务器与多个客户端进行数据交互的过程。

    1)嵌套字初始 化:调用函数Socket(),成功返回一套接字文件描述符赋值给listenfd.然后将结构体servaddr清空嵌套字初始化,连接服务器,打开一 个网络通信端口,创建服务器结构体,绑定端口号和服务地址,将客户端套接字描述符赋值到allset rest集中,调用listen函数声明服务器处于监听状态最大允许接入客户端为20个将监听到的文件描述符listenfd赋给maxfd,给maxi 赋初值为-1,使用for循环对数组client[]初始化

    for (i = 0; i < FD_SETSIZE; i++)    

                    client[i] = -1;

    将allset清空,将listenfd文件描述符添加到&allset描述符集中

    2)服务器与客户端进行三次握手:

    将allset 集赋值给rest 调用select函数将客户端与服务器的连接数保存在nready中,如果nready小于0则返回出错,nready大于零件描述符listenfd在 集合rset中,就执行Accept()函数,返回一个新的文件描述符赋给connfd.打印出客户端的ip地址与端口号.

    for ( ; ; ) {

                    rset = allset;        /* structure assignment */

                    nready = select(maxfd+1, &rset, NULL, NULL, NULL);

                    if (nready < 0)

                            perr_exit("select error");

                    if (FD_ISSET(listenfd, &rset)) { /* new client connection */

                            cliaddr_len = sizeof(cliaddr);

                            connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);

                            printf("received from %s at PORT %d ",

                                   inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),

                                   ntohs(cliaddr.sin_port));

    将新得到的文件描述符connfd保存到数组client[]中.把新得到的文件描述connfd符写入allset集合中

    for (i = 0; i < FD_SETSIZE; i++)

                                    if (client[i] < 0) {

                                            client[i] = connfd; /* save descriptor */

                                            break;

    判断客户端的连接数是否达到最大的上限值,如果达到就输出错误。

    if (i == FD_SETSIZE) {

                                    fputs("too many clients ", stderr);

                                    exit(1);

                            }

    将新文件描述符 添加到allset集中,通过if语句把allset中的文件描述符和i的最大值找出来分别赋给maxfd,maxi.把nready的值自减1,当 nready为0,没有更多的文件描述符,结束本次循环.此时就只有一个文件描述符listenfd,所以nready的值是1,自减后不等于0就不执行 con进入for语句把connfd赋给sockfd因为等于0,就结束本次循环.进入下次for循环,重新监听来自客户端的连接请求.

    for循环检查 所有客户端数,if ( (sockfd = client[i]) < 0))没有客户端数据请求,if语句判断sockfd文件描述符是否在rset文件集中。如果读出的客户端数据为0关闭连接从allset文件描述符中清 除文件描述,除此把客户端传入的数据进行处理,处理完后返回客户端。

    客户端1

    [root@bogon Desktop]# gcc client.c -o client

    [root@bogon Desktop]# ./client

    ff

    FF

    fdsadfdsfdsf

    FDSADFDSFDSF

    客户端2

    [root@bogon ~]# cd /root/Desktop/

    [root@bogon Desktop]# gcc client.c -o client

    [root@bogon Desktop]# ./client

    dshfasdjf

    DSHFASDJF

    fsdafdsf

    FSDAFDSF

    客户端3

    [root@bogon ~]# cd /root/Desktop/

    [root@bogon Desktop]#  gcc client.c -o client

    [root@bogon Desktop]# ./client

    kkkdslfdlfs

    KKKDSLFDLFS

    ff

    FF

    服务器端

    [root@bogon Desktop]# gcc server.c -o server

    [root@bogon Desktop]# ./server

    received from 127.0.0.1 at PORT 58471

    received from 127.0.0.1 at PORT 58472

    received from 127.0.0.1 at PORT 58473

     

    <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>
    阅读(373) | 评论(0) | 转发(0) |
    给主人留下些什么吧!~~
    评论热议
  • 相关阅读:
    阿里巴巴电商搜索推荐实时数仓演进之路
    阿里云发布边缘计算视频上云解决方案 为海量视图处理提供城市级云基础设施
    MySQL设置所有IP地址都可以访问数据库
    HTML5中的data-*属性和jQuery中的.data()方法使用
    21. 合并两个有序链表 *****
    链表相交
    链表的中间节点
    剑指 Offer 24. 反转链表 *****
    从尾到头打印链表
    返回倒数第k个节点
  • 原文地址:https://www.cnblogs.com/ztguang/p/12647548.html
Copyright © 2011-2022 走看看