Chinaunix首页 | 论坛 | 博客
  • 博客访问: 6655915
  • 博文数量: 1159
  • 博客积分: 12444
  • 博客等级: 上将
  • 技术积分: 12570
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-13 21:34
文章分类

全部博文(1159)

文章存档

2016年(126)

2015年(350)

2014年(56)

2013年(91)

2012年(182)

2011年(193)

2010年(138)

2009年(23)

分类: 嵌入式

2011-06-17 15:14:25

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\n",

                               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\n", 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\n",

                               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\n", 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

 

阅读(1256) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~