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) |
    给主人留下些什么吧!~~
    评论热议
  • 相关阅读:
    LeetCode 24. Swap Nodes in Pairs (两两交换链表中的节点)
    LeetCode 1041. Robot Bounded In Circle (困于环中的机器人)
    LeetCode 1037. Valid Boomerang (有效的回旋镖)
    LeetCode 1108. Defanging an IP Address (IP 地址无效化)
    LeetCode 704. Binary Search (二分查找)
    LeetCode 744. Find Smallest Letter Greater Than Target (寻找比目标字母大的最小字母)
    LeetCode 852. Peak Index in a Mountain Array (山脉数组的峰顶索引)
    LeetCode 817. Linked List Components (链表组件)
    LeetCode 1019. Next Greater Node In Linked List (链表中的下一个更大节点)
    29. Divide Two Integers
  • 原文地址:https://www.cnblogs.com/ztguang/p/12647548.html
Copyright © 2011-2022 走看看