zoukankan      html  css  js  c++  java
  • server-client 服务器 客户端 李春玲

     

    09计算机应用技术2班  李春玲 0906042004
    ------------------------------------ sever.c ------------------------------------
    /*------------------------------------------------------------------------------------
    注释: 服务器端负责接受客户端的数据请求,把对一个客户端的数据转发给每个与服务器建立链接的客户端。
    下面的指令是生成可执行文件:
    [root@localhost zy]# gcc server.c -o ser
    -------------------------------------------------------------------------------------*/

     

    / server.c */

    #include

    #include

    #include

    #include

    #include "wrap.h"

     

    #define MAXLINE 80/*通道最大为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;

           char buf[MAXLINE];

           char str[INET_ADDRSTRLEN];

           socklen_t cliaddr_len;

           struct sockaddr_in       cliaddr, servaddr;

     

           listenfd = Socket(AF_INET, SOCK_STREAM, 0);/*成功返回一套接字文件描述符赋给listenfd,,如果socket()调用出错则返回-1*/

     

           bzero(&servaddr, sizeof(servaddr));/*将结构体servaddr清零*/

           servaddr.sin_family      = AF_INET;/*设置地址类型为AF_INET*/

           servaddr.sin_addr.s_addr = htonl(INADDR_ANY);/*网络地址为INADDR_ANY,INADDR_ANY表示本地的任意IP地址*/

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

     

           Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));/*bind将本地网络地址和端口号与服务器网络地址和端口号绑定在一起,实现本地与服务器的通信.bind()成 功返回0,失败返回-1*/

     

           Listen(listenfd, 20);/*监听listenfd的状态,并且最多允许监听20个,如果接收到更多的连接请求就忽略.*/

     

           maxfd = listenfd;              /* 给maxfd初始化 */

           maxi = -1;                     /* 给maxi初始化 */

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

                  client[i] = -1;       /* 给client[]初始化为-1 */

           FD_ZERO(&allset);/*cccallset集合,用于存放socket文件描述符*/

           FD_SET(listenfd, &allset);/*把监听到的文件描述listenfd符写入allset集合中*/

     

           for ( ; ; ) {

                  rset = allset;      

                  nready = select(maxfd+1, &rset, NULL, NULL, NULL);/*可以监听多个文件描述符,当有数据到达时就处理,并返回更新的个数给nready,没有数据到达就阻塞*/

                  if (nready < 0)/*当nready小于0时出错*/

                         perr_exit("select error");

     

                  if (FD_ISSET(listenfd, &rset)) { /*测试文件描述符listenfd是否在rset集中 */

                         cliaddr_len = sizeof(cliaddr);

                         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)),/*将cliaddr.sin_addr地址装换成字符串,并返回字符首地址*/

                                ntohs(cliaddr.sin_port));/*网络字节序转换为主机字节序/**/

     

                         for (i = 0; i < FD_SETSIZE; i++)/*查找最小没用的数组元素,并将文件描述符connfd保存起来*/

                                if (client[i] < 0) {

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

                                       break;

                                }

                         if (i == FD_SETSIZE) {/*如果最小没用的数组元素与数组最大容量相等时出错,有太多的客户端*/

                                fputs("too many clients ", stderr);

                                exit(1);

                         }

     

                         FD_SET(connfd, &allset);/* 把新得到的文件描述connfd符写入allset集合中 */

                         if (connfd > maxfd)/*设置最大文件描述符*/

                                maxfd = connfd; /* for select */

                         if (i > maxi)/*设置i的最大值*/

                                maxi = i;       /* max index in client[] array */

     

                         if (--nready == 0)/*当nready为0,没有更多的文件描述符,结束本次循环*/

                                continue;       /* no more readable descriptors */

                  }

     

                  for (i = 0; i <= maxi; i++) {       /* check all clients for data */

                         if ( (sockfd = client[i]) < 0)

                                continue;

                         if (FD_ISSET(sockfd, &rset)) {

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

                                       /* connection closed by client */

                                       Close(sockfd);/*如果客户端关闭了,服务器端也关闭*/

                                       FD_CLR(sockfd, &allset);/*从allset清除sockfd的文件描述符*/

                                       client[i] = -1;

                                } else {/*如果客户端没有关闭,服务器接受来自客户端的数据,并处理,完成后并返回给客户端*/

                                       int j;

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

                                              buf[j] = toupper(buf[j]);/*将小写转换成大写*/

                                       Write(sockfd, buf, n);/*将处理后的数据从buf中写回客户端*/

                                }

     

                                if (--nready == 0)/*当nready=0时,数据处理完,结束本次循环*/

                                       break;       /* no more readable descriptors */

                         }

                  }

           }

    }

     

     

     

    /*执行过程:

       调 用函数Socket(),成功返回一套接字文件描述符赋值给listenfd.然后将结构体servaddr清空,设置ipv4地址类型为 AF_INET,NADDR_ANY为本地的任意IP地址,端口号宏定义为8000.调用函数Bind(),将本地的套接字listenfd与服务器网络 地址和端口号绑定在一起,在服务器端调用函Listen()数来监听客户端状态.将监听到的文件描述符listenfd赋给maxfd,给maxi赋初值 为-1,使用for循环对数组client[]初始化,将allset集合清空,把监听到的文件描述listenfd符写入allset集合中,进入 for循环,把allset里的文件描述符赋给rset(把listenfd的文件描述符赋给rset).

       调用select函数,当客户端有连接请求时,将客户端请求个数返回给nready,如果有一个请求,则nready = 1.if判断nready不小于0,不出错.此时文件描述符listenfd在集合rset中,就执行Accept()函数,返回一个新的文件描述符赋给 connfd.打印出客户端的ip地址与端口号.将新得到的文件描述符connfd保存到数组client[]中.把新得到的文件描述connfd符写入 allset集合中,通过if语句把allset中的文件描述符和i的最大值找出来分别赋给maxfd,maxi.把ready的值自减1,当 nready为0,没有更多的文件描述符,结束本次循环.此时就只有一个文件描述符listenfd,所以nready的值是1,自减后不等于0就不执行 con进入for语句把connfd赋给sockfd因为等于0,就结束本次循环.进入下次for循环,重新监听来自客户端的连接请求.

       在 本次循环中在rset,allset中有俩个文件描述符分别是listenfd,connfd,如果listenfd没有数据到达,connfd有数据到 达,则由select得到nready值为1,if判断rset中的第一个文件描述符listenfd没有连接请求,退出if语句,进入下一个for循 环.将connfd赋给sockfd.因为connfd有连接请求,并判断客户端没有关闭连接,接收来自客户端的数据并将小写装换为大写重新返回给客户 端;如果客户端关闭连接,服务器端也关闭连接,并从allset清除sockfd的文件描述符.把ready的值自减1,当nready为0,没有更多的 文件描述符,结束本次循环.此时就只有一个文件描述符connfd,所以nready的值是1,自减后等于0,就结束本次循环.进入下次for循环,重新 监听来自客户端的连接请求.

       在 本次循环中在rset,allset中有俩个文件描述符分别是listenfd,connfd,如果linstenfd和connfd都有连接请求,则 select返回值是2,nready旳值也是2.if判断nready不小于0,不出错.此时文件描述符listenfd在集合rset中,就执行 Accept()函数,返回一个新的文件描述符赋给connfd.打印出客户端的ip地址与端口号.将新得到的文件描述符connfd1保存到数组 client[]中.把新得到的文件描述connfd1符写入allset集合中,此时allset集合中有三个文件描述符分别是listenfd、 connfd、connfd1.通过if语句把allset中的文件描述符和i的最大值找出来分别赋给maxfd,maxi.把ready的值自减 1,nraedy的值是1,1不等于0,就不执行continue,进入for语句把connfd赋给sockfd,因为connfd有连接请求并判断客 户端没有关闭连接,接收来自客户端的数据并将小写装换为大写重新返回给客户端;如果客户端关闭连接,服务器端也关闭连接,并从allset清除 sockfd的文件描述符.把ready的值自减1,nready为0,没有更多的文件描述符,结束本次循环.进入下次for循环,重新监听来自客户端的 连接请求.

     

     

    实验执行结果:

    服务器端:

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

    [root@localhost Desktop]# ./server

    received from 127.0.0.1 at PORT 38503

    received from 127.0.0.1 at PORT 46788

    received from 127.0.0.1 at PORT 46790

     

    客户端1:

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

    [root@localhost Desktop]# ./client

    hello  

    HELLO

    world

    WORLD

    heihei

    HEIHEI

     

    客户端2:

     

    [root@localhost Desktop]# ./client

    huhlk

    HUHLK

    huahuhu

    HUAHUHU

    hhhh

    HHHH

    客户端3:

    [root@localhost Desktop]# ./client

    cai

    CAI

    neng

    NENG

    shuochu

    SHUOCHU

    mmmmmmooqi

    MMMMMMOOQI

     

    关闭服务器端后的客户端:

    [root@localhost Desktop]# ./client

    connect error: Connection refused

    [root@localhost Desktop]#

     

     

     

    在打开服务器和关闭服务器端后的客户端:

    [root@localhost Desktop]# ./client

    huhlk

    HUHLK

    huahuhu

    HUAHUHU

    hhhh

    HHHH

    xinjing

    the other side has been closed.

    j

    [root@localhost Desktop]#

     

                                   */

     

     

     

     

    <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>
    阅读(727) | 评论(0) | 转发(1) |
    给主人留下些什么吧!~~
    评论热议
  • 相关阅读:
    eclipse GWT开发环境的离线布置方法
    Eclipse(Myeclipse)安装GoogleGWT
    ASP.NET中的文件上传大小限制的问题
    ActivityCapture
    android camera 摄像头预览画面变形
    MUST_COMPLETE
    Stay true to yourself
    Android4.4 ContentResolver查询图片无效 及 图库删除 增加图片后,ContentResolver不更新的问题解决
    android 7.0以上共享文件(解决调用系统照相和图片剪切出现的FileUriExposedException崩溃问题)
    扫描指定目录下所有图片文件
  • 原文地址:https://www.cnblogs.com/ztguang/p/12647517.html
Copyright © 2011-2022 走看看