Chinaunix首页 | 论坛 | 博客
  • 博客访问: 47474
  • 博文数量: 25
  • 博客积分: 960
  • 博客等级: 准尉
  • 技术积分: 280
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-14 12:39
文章分类
文章存档

2011年(1)

2009年(20)

2008年(4)

我的朋友

分类: C/C++

2009-04-23 18:27:11

#include
#include
#include
#include
#include
#include
#include
#include 
#include 
#include 
#include 
#include 
#include
#define   HOSTLEN  256
#define PORT 8080
#define   BACKLOG  2

int make_server_socket(int portnum, int backlog)
{
 struct  sockaddr_in   saddr;
 int sock_id;
 if ((sock_id = socket(AF_INET, SOCK_STREAM, 0)) == -1)
 {
  perror("creating socket failed.");
  exit(1);
 }
 int opt = SO_REUSEADDR;
 setsockopt(sock_id, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
 bzero(&saddr,sizeof(saddr));
 saddr.sin_family = AF_INET;
 saddr.sin_port = htons(portnum);
 saddr.sin_addr.s_addr = htonl(INADDR_ANY); 
 if(bind(sock_id,(struct sockaddr *)&saddr,sizeof(struct sockaddr)) == -1)
 {
  perror("bind error.");
  exit(1);
 }
 if ( listen(sock_id, backlog) != 0 )
  return -1;
 return sock_id;
}
setup(pthread_attr_t *attrp)
{
 pthread_attr_init(attrp);//线程初始化  作用???
 pthread_attr_setdetachstate(attrp,PTHREAD_CREATE_DETACHED);
 //设置为PTHREAD_CREATE_DETACHED 以分离状态启动线程
 //或者设置为PTHREAD_CREATE_JOINABLE,正常启动线程
 /*
 线程属性结构如下:
 typedef struct
 {
       int       detachstate;   线程的分离状态
       int       schedpolicy;  线程调度策略
       struct sched_param   schedparam;  线程的调度参数
       int   inheritsched;  线程的继承性
       int   scope;       线程的作用域
       size_t    guardsize;   线程栈末尾的警戒缓冲区大小
       int     stackaddr_set;
       void *   stackaddr;   线程栈的位置
       size_t    stacksize;    线程栈的大小
 }pthread_attr_t;
 */
 //time(&server_started);
 //server_requests = 0;
 //server_bytes_sent = 0;
}
void *handle_call(void *fdptr)
{//接到的是一个句柄
 FILE *fpin;//定义一个指向文件的指针
 char request[BUFSIZ];//定义一个缓存用于存放接收到的数据
 int fd ;//再定义一个临时套接字文件描述符
 fd = *(int *)fdptr;//将传过来的参数转成套接字文件描述符
 free(fdptr);//释放内存    
 fpin = fdopen(fd, "r");//打开套接字文件描述符  而得到一个文件描述符   
 fgets(request,BUFSIZ,fpin); //将fpin里面的内容读入request数组中 
//got a call on 4: request = GET /htdoc/readerchaxun.html?shuming=20040502215&Submit=ChaXun HTTP/1.1
//sanitized version is htdoc/readerchaxun.html?shuming=20040502215&Submit=ChaXun
 printf("got a call on %d: request = %s", fd, request);//向终端打印得到的信息
 skip_rest_of_header(fpin);//再一次的处理收到的信息  作用????
 process_rq(request, fd);//处理客户请求  
 fclose(fpin);//最后关
}
skip_rest_of_header(FILE *fp)//这里的参数是文件描述符
{
 char buf[BUFSIZ];//用于存放数据
 while( fgets(buf,BUFSIZ,fp) != NULL && strcmp(buf,"\r\n") != 0 )
  ;//fgets和上面一样,strcmp 比较字符串是否相等 相等为1
}
process_rq( char *rq, int fd)
{
 char cmd[BUFSIZ], arg[BUFSIZ];
 if ( sscanf(rq, "%s%s", cmd, arg) != 2 )//把收到的信息以空格为分隔,分别存入两个数组之中
  //后面的版本信息不接收  GET  /index.html  HTTP/1.0
  return;
 sanitize(arg);//对请求的路经分解  比如 /htdoc/index.html
 printf("sanitized version is %s\n", arg);//把转化好的输出
 //printf("the cmd is =",cmd);
 //cmd=htdoc/readerchaxun.html?shuming=20040502215&Submit=Submit
 //htdoc/readerchaxun.html?shuming=20040502215&userpassword=123456&Submit=ChaXun
 /*
 分析:先用get方法接收来的url字符串放入cmd数组之中
 1、先判断有没有 “?”
   如果有,就按原来的执行。
   如果没有,就先把“?”
 之后的字符串提起出来。放入另外一个数组data[]之中
   再从data[]数组中按下面的格式提起出来.
 */
 // 把它们分别提起出来:
 //:htdoc/readerchaxun.html
 //:shuming
 //:20040502215
 //:userpassword
 //:123456
 //:Submit
 //:ChaXun
 
 if ( strcmp(cmd,"GET") != 0 )//对第一个数组判断
  not_implemented();//如果被调用,说明收到的不是GET 退出
 else if ( built_in(arg, fd) )//给客户端以送确认信号
  ;
 else if ( not_exist( arg ) )//提供文件名字,获取文件对应属性
  do_404(arg, fd);
 else if ( isadir( arg ) )//判断是不是当前目录?是
  //do_ls( arg, fd );//读取文件目录信息
  do_index(fd);//读取默认index.html
 else
  do_cat( arg, fd );//最后读取文件
}
sanitize(char *str)
{
 char *src, *dest;//定义两个char 指针变量原和目的
 src = dest = str;//对三个同学给传进来的值
 //注意这里str是数组如:arg[]={""/","i","n","d","e","x",".","h","t","m","l"}  /index.html
 while( *src )
 {
  if( strncmp(src,"/../",4) == 0 )//字符串比较,相等反回0
   src += 3;//目的是去掉/../
  else if ( strncmp(src,"//",2) == 0 )
   src++;//目的是去掉//
  else
   *dest++ = *src++;//将去掉后的src给dest
 }
 *dest = '\0';//最后这里得到的是一个完全的目录
 if ( *str == '/' )
  strcpy(str,str+1);//???
 if ( str[0]=='\0' || strcmp(str,"./")==0 || strcmp(str,"./..")==0 )
  strcpy(str,".");
}

built_in(char *arg, int fd)
{
 FILE *fp;//定义一个文件描述符
 if ( strcmp(arg,"status") != 0 )//status 是什么意思???
  return 0;
 http_reply(fd, &fp, 200, "OK", "text/plain",NULL);//发送确认信号
 //fprintf(fp,"Server started: %s", ctime(&server_started));
 //fprintf(fp,"Total requests: %d\n", server_requests);
 //fprintf(fp,"Bytes sent out: %d\n", server_bytes_sent);
 fclose(fp);
 return 1;
}
http_reply(int fd, FILE **fpp, int code, char *msg, char *type, char *content)
{
 FILE *fp = fdopen(fd, "w");//先打开客户端套接字文件描述符
 //int bytes = 0;
 if ( fp != NULL )
 {//打开成功,向客户端写入信息
  //bytes = fprintf(fp,"HTTP/1.0 %d %s\r\n", code, msg);
  fprintf(fp,"HTTP/1.0 %d %s\r\n", code, msg);//向客户端写入信息
  //bytes += fprintf(fp,"Content-type: %s\r\n\r\n", type);
  fprintf(fp,"Content-type: %s\r\n\r\n", type);
  if ( content )
   //bytes += fprintf(fp,"%s\r\n", content);
   fprintf(fp,"%s\r\n", content);
 }
 fflush(fp);//刷新fp
 if ( fpp )
  *fpp = fp;
 else
  fclose(fp);
 //return bytes;
 return 0;
}
not_implemented(int fd)
{
 http_reply(fd,NULL,501,"Not Implemented","text/plain","That command is not implemented");
}
do_404(char *item, int fd)
{
 http_reply(fd,NULL,404,"Not Found","text/plain","The item you seek is not here");
}
isadir(char *f)
{
 struct stat info;
 return ( stat(f, &info) != -1 && S_ISDIR(info.st_mode) );
 //st_mode 文件对应的模式,文件,目录等
}
not_exist(char *f)
{
 struct stat info;//定义一个结构体  有什么用??
 return( stat(f,&info) == -1 );//通过文件描述符获取文件对应的属性
 //提供文件名字,获取文件对应属性
}
/*
do_ls(char *dir, int fd)
{//arg fd  为传进来的参数
 DIR       *dirptr;
 struct dirent *direntp;
 FILE       *fp;
 //int       bytes = 0;
 //bytes = http_reply(fd,&fp,200,"OK","text/plain",NULL);
 http_reply(fd,&fp,200,"OK","text/plain",NULL);
 //bytes += fprintf(fp,"Listing of Directory %s\n", dir);
 fprintf(fp,"Listing of Directory %s\n", dir);
 if ( (dirptr = opendir(dir)) != NULL )
 {//打开成功
  while( direntp = readdir(dirptr) )
  {
   //bytes += fprintf(fp, "%s\n", direntp->d_name);
   fprintf(fp, "%s\n", direntp->d_name);
  }
  closedir(dirptr);
 }
 fclose(fp);
 //server_bytes_sent += bytes;
}
*/
char * file_type(char *f)
{//反回的是文件类型
 char *cp;
 if ( (cp = strrchr(f, '.' )) != NULL )//这里用strrchr 是提起 一点之后的字符串  再反回给cp
                                      //strrchr()在串中查找指定字符的最后一个出现
  return cp+1;//cp +1 是什么意思 ?? 指的是以一点之后的字符串 
                 //不要反回一点再加字符串
 return "";
}
do_index(int fd)
{
 char  *f1="index.html";
 char *type = "text/html";
 FILE *fpsock, *fpfile;//再定义两个文件描述符
 int c;
 fpsock = fdopen(fd, "w");//打开客户端套接字 反回一个文件描述符  用于写数据
 fpfile = fopen( f1 , "r");//打开服务器端的文件  反回一个文件描述符  用于读取数据
 if ( fpsock != NULL && fpfile != NULL )
 {//如果两个都成功  才是做下面的动作
  http_reply(fd,&fpsock,200,"OK",type,NULL);//通知客户端,准备接收数据
  while( (c = getc(fpfile) ) != EOF )//读取数据  为什么不用read ???
  {
   putc(c, fpsock);//写入数据  为什么不可以用write ???
  }
  fclose(fpfile);//关
  fclose(fpsock);//关
 }
}
do_cat(char *f, int fd)
{//这里f=arg   fd=fd
 char *extension = file_type(f);//这里将得到的是文件的后缀
 char *type = "text/plain";//定义并初始化这字符串
 FILE *fpsock, *fpfile;//再定义两个文件描述符
 int c;
 if ( strcmp(extension,"html") == 0 )
  type = "text/html";
 else if ( strcmp(extension, "gif") == 0 )
  type = "image/gif";
 else if ( strcmp(extension, "jpg") == 0 )
  type = "image/jpg";
 else if ( strcmp(extension, "jpeg") == 0 )
  type = "image/jpeg";
 
 fpsock = fdopen(fd, "w");//打开客户端套接字 反回一个文件描述符  用于写数据
 fpfile = fopen( f , "r");//打开服务器端的文件  反回一个文件描述符  用于读取数据
 if ( fpsock != NULL && fpfile != NULL )
 {//如果两个都成功  才是做下面的动作
  http_reply(fd,&fpsock,200,"OK",type,NULL);//通知客户端,准备接收数据
  while( (c = getc(fpfile) ) != EOF )//读取数据  为什么不用read ???
  {
   putc(c, fpsock);//写入数据  为什么不可以用write ???
   //bytes++;
  }
  fclose(fpfile);//关
  fclose(fpsock);//关
 }
}
main(int ac, char *av[])
{
 int  sock, fd;
 int *fdptr;
 pthread_t worker;
 pthread_attr_t attr;//定义一个线程变量
 void *handle_call(void *);//反回????定义线程调用函数
 sock = make_server_socket(PORT,BACKLOG);//反回客户端请求ID号
 if ( sock == -1 ) { perror("making socket"); exit(2); }
 setup(&attr);//设置线程以分离状态启动
 while(1)
 {
  fd = accept( sock, NULL, NULL );//得到的是客户端请求的端口套接字描述符
  //server_requests++;
  fdptr = malloc(sizeof(int));//申请分配内存空间,放一个句柄
  *fdptr = fd;//把请求的放在句柄
  pthread_create(&worker,&attr,handle_call,fdptr);//创建一个线程
  //传参数  fdptr 到handle_call之中
 }
}
阅读(604) | 评论(0) | 转发(0) |
0

上一篇:表单html

下一篇:C语言插入MySQL insert

给主人留下些什么吧!~~