Chinaunix首页 | 论坛 | 博客
  • 博客访问: 6658016
  • 博文数量: 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:18:09

班级:09计应用二班  姓名:郑明莉  学号:0906042007

 

/* server.c */

#include

#include

#include

#include

#include "wrap.h"

 

#define MAXLINE 80 //通道大小

#define SERV_PORT 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); //打开一个IPV4的TCP连接端口

bzero(&servaddr, sizeof(servaddr));//清空服务器的地址

servaddr.sin_family = AF_INET;//服务器的地址类型为IPV4

      servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//服务器允许任何客户端访问

servaddr.sin_port= htons(SERV_PORT);//服务器端口设为8000

Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));//把监听端口和服务器通信端口绑定

Listen(listenfd, 20);开始监听服务器通信端口

maxfd = listenfd;            /* initialize */把最新的连接描述符赋值给maxfd,三次握手第二步;

maxi = -1;                  /* index into client[] array */maxi初始化为-1;

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

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

      FD_ZERO(&allset);把allset清空

      FD_SET(listenfd, &allset);把listenfd描述符添加进allset文件描述符集

 

      for ( ; ; ) {

            rset = allset;      /* structure assignment */把连接赋值给rset

            nready = select(maxfd+1, &rset, NULL, NULL, NULL);把已连接的描述符保存在nready里;

            if (nready < 0)

                  perr_exit("select error");

 

            if (FD_ISSET(listenfd, &rset)) { /* new client connection */如果listenfd已经在rset集里,则执行此命令下面的语句;

                  cliaddr_len = sizeof(cliaddr);客户端地址长度

                  connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);把新的描述符给connfd,接受listenfd连接,三次握手完成;

 

                  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++)

                        if (client[i] < 0) {

                              client[i] = connfd; /* save descriptor */把已连接的客户端文件描述符保存在client 数组里

                              break;

                        }

                  if (i == FD_SETSIZE) {

                        fputs("too many clients\n", stderr);如果连接已满则输出错误信息

                        exit(1);错误输出

                  }

 

                  FD_SET(connfd, &allset);      /* add new descriptor to set */将新的文件描述符添加进allset 里!

                  if (connfd > maxfd)

                        maxfd = connfd; /* for select */把最新的文件描述符保存在maxfd里

                  if (i > maxi)

                        maxi = i;      /* max index in client[] array */把已有的连接总数保存在maxi里

 

                  if (--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)) {如果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)如果没有客户写入数据则结束这个循环体

                              break;      /* no more readable descriptors */

                  }

            }

      }

}

 

执行过程:

Listenfd=socket(AF_INET,SOCK_STREAM,0)从此句开始,

   调用函数Socket(),打开一个IPV4的TCP连接端口,返回一套接字文件描述符赋值给监听套接字listenfd.再把servaddr清空,IPV4的地址类型设置为AF­_INET,服务器允许任何客户端访问,NADDR-ANY为本地的任意IP地址,服务器端口设为8000;

   调 用Bind函数,将本地监听端口与服务器通信端口绑定在一起,在服务器端调用Listen函数来监听客户端状态。将监听到的文件描述符Listenfd赋 值给maxfd,maxi赋值为-1,表示客户端没有连接,client[]进行初始化,把allset清空,再把监听到的文件描述符 listenfd 添加到文件描述符集allset中;用for循环把allset里的文件描述符给rset,这时allset里有一个listenfd文件描述符.    调 用select函数,如果客户端有连接请求时,将客户端请求个数返回给nready,若有一个请求时,则nready=1,用if判断nready不小于 0,则不出错,这时rset文件描述符集合中有listenfd文件描述符,执行Accept()函数,相当于调用一个socket,生成新的套接字把新 套接字描述符给connfd,再打印出客户端的IP地址,端口号,用子循环for,从低位开始查找空位,再赋值放connfd文件描述符,就是把新得到的文件描述符connfd赋给数组client[],再把新得到的connfd写入 allset文件描述符集合中,此时allset文件描述符集中有listenfd和connfd两个,用if 把allset中的文件描述符和I 最大值找出来分别赋给mxfd ,maxi.nready==0时,没有更多的文件描述符,结束本次循环,这是就只有一个文件描述符listenfd,因此nready的值为1,--nready时不等0,就不执行continue,进入for 语句把connfd赋给sockfd,这时等于0,结束本次循环.再次执行for循环,监听来自客户端的连接请求. Rset和allset中都有两个文件描述符listenfd,connfd,如果connfd有数据到达,listenfd没有数据到达时,调用select,得到nready 的值 是1,在for 循环中把 connfd给sockfd,如 果客户端和服务器关闭连接,从allset清除sockfd文件描述符,把nready的值自减1,当nready的值为0时,结束本次循环.在此 时,rset ,allset中有 listenfd,connfd,,如果都有连接请求,select返回2,nready为2,if判断出nread的值不小于0, 正确,listendfd在rset 中,执行Accept函数.打印客户端IP地址和端口号,新得到的connfd1保存到client[]

再写入allset 中,这时有listend,connfd,connfd1三个文件描述符,找出最大值给maxfd,maxi,--nready为1,直接进入for把connfd给sockfd,接收来自客户端的数据,把小写转换成大写返回给客户端.

 

 

 

执行结果:

服务器端

[root@localhost zml]# gcc server.c -o server
[root@localhost zml]# ./server
received from 127.0.0.1 at PORT 50121
received from 127.0.0.1 at PORT 50124


终端一

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

abc

ABC

zhengmingli

ZHENGMINGLI

qianrushibanji

 





终端二

[root@localhost zml]# ./client
abc
ABC
zhengmingli
ZHENGMINGLI

qianrushibanji

 

 

终端三

[root@localhost zml]# ./client

qianrushibanji

QIANRUSHIBANJI

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

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