web server服务程式编写

本文介绍了一个用C语言编写的特殊Web Server程序,该程序能在FreeBSD和Windows (Cygwin)环境下运行,通过HTTP 1.0协议接收GET请求并返回PNG格式的图片。
  1. 本程序是一个提供特殊服务的Web Server。该程序是一个Daemon程序,用单进程+I/O多路转换(select)的方式接收Http的Get请求,请求中是一个字符串(可以是数字或者字母),返回一个PNG格式的图片,整个过程符合Http 1.0协议。
  2.         本程序类似于网站上常用的生成“验证码”的程序。
  3.         本程序在FreeBSD环境下开发完成,并可同时在FreeBSD和Windows (Cygwin)下编译运行。FreeBSD环境安装有gd-1.8.4库,Cygwin环境安装有libpng-1.2.8和gd-2.0.33库,用于生成PNG图片。
  4.         整个程序用C语言完成,源代码如下:
  5. /***************************************************************************
  6.  * Copyright (C) 2004-2005 XiongBin Xiong  All rights reserved
  7.  * References: Stevens,W.R. 1992. Advanced Programming in the UNIX Environment. Addison-Wesley.
  8.  *                    Stevens,W.R. 1998. UNIX Network Programming Volum1.Prentice Hall PTR
  9.  */
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #include <sys/socket.h>
  13. #include <netinet/in.h>
  14. #include <sys/time.h>
  15. #include <signal.h>
  16. #include <fcntl.h>
  17. #include <stdio.h>
  18. #include <time.h>
  19. #include <syslog.h>
  20. #include <errno.h>
  21. #include <string.h>
  22. #include <stdarg.h>
  23. #include <unistd.h>
  24. #include <gd.h>
  25. #include <gdfontg.h>  /* 定义了"gdFontGiant"字体结构 */
  26. #define MAXCLIENT 1024  /* 数组client的最大值,即此服务器所能处理的最大客户数 */
  27. #define BUFFSIZE 4096
  28. int daemon_init(const char *); /* daemon进程初始化函数 */
  29. int getpng(char *,char *,int); /* png图片生成函数 */
  30. void sendFile(intchar *); /* 发送文件到客户端 */
  31. void log_sys(const char *, ...);
  32. static void log_doit(intintconst char *, va_list ap);
  33. int
  34. main(int argc, char **argv)
  35. {
  36.  int   i,maxi,maxfd,listenfd,connfd,hfd,nready,client[MAXCLIENT];
  37.  char   *p,*pp, recvbuf[BUFFSIZE];
  38.  ssize_t   recvlen;
  39.  fd_set   rset, allset;
  40.  struct sockaddr_in servaddr;
  41.  daemon_init(argv[0]);    /* 成为daemon进程 */
  42.  listenfd=socket(AF_INET, SOCK_STREAM, 0);
  43.  bzero(&servaddr, sizeof(servaddr));  /* 初始化套借口地址结构 */
  44.  servaddr.sin_family      =AF_INET;
  45.  servaddr.sin_addr.s_addr =htonl(INADDR_ANY);
  46.  servaddr.sin_port        =htons(80);
  47.  bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
  48.  listen(listenfd,5);
  49.  maxfd=listenfd;
  50.  maxi=-1;
  51.  for(i=0;i<MAXCLIENT;i++)
  52.   client[i]=-1;  /* 用-1初始化数组client[] */
  53.  FD_ZERO(&allset);
  54.  FD_SET(listenfd, &allset); /* 初始化allset */
  55.  for(;;){
  56.   rset=allset;
  57.   nready=select(maxfd+1, &rset, NULL, NULL, NULL);
  58.   if(FD_ISSET(listenfd, &rset)){  /* 新用户连接 */
  59.    connfd=accept(listenfd,(struct sockaddr *)NULL,NULL);
  60.    for(i=0;i<FD_SETSIZE;i++)
  61.     if(client[i]<0){
  62.      client[i]=connfd; /* 保存描述符 */
  63.      break;
  64.     }
  65.    if(i==MAXCLIENT)  /* 连接过多 */
  66.     log_sys("connection overflow");
  67.    FD_SET(connfd, &allset); /* 将新描述符加入allset中 */
  68.    if(connfd>maxfd)
  69.     maxfd=connfd;  /* 最大描述符的值 */
  70.    if(i>maxi)
  71.     maxi=i;   /* client[]数组的最大元素标号 */
  72.    if(--nready<=0)
  73.     continue;  /* 没有可读的描述符了 */
  74.   }
  75.   for(i=0;i<=maxi;i++){ /* check all clients for data */
  76.    if((hfd=client[i])<0)
  77.     continue;
  78.    if(FD_ISSET(hfd, &rset)){
  79.     if((recvlen=recv(hfd,recvbuf,sizeof(recvbuf),0))==0){
  80.       /* 用户断开连接 */
  81.      close(hfd);
  82.      FD_CLR(hfd, &allset);
  83.      client[i]=-1;
  84.     }else
  85.      if(strncmp(recvbuf,"GET",3)==0){ /* 判断请求
  86. 类型是否为GET */
  87.       p=strchr(recvbuf+3,'/'); /* 找请求
  88. 中'/'的匹配之处 */
  89.       if(p!=0){
  90.        pp=strstr(recvbuf+3,"HTTP/1."); /*
  91. 找请求中"HTTP/1."的匹配之处 */
  92.        if(pp!=0){
  93.         p++;
  94.         pp--;
  95.         *pp='/0'/* 获取用户
  96. 输入的字符或数字串 */
  97.         getpng
  98. ("/tmp/pass.png",p,strlen(p)); /* 生成PNG图片 */
  99.         sendFile
  100. (hfd,"/tmp/pass.png"); /* 发送PNG图片给用户 */
  101.         close(hfd);
  102.         FD_CLR(hfd, &allset);
  103.         client[i]=-1;
  104.        }
  105.       }
  106.      }
  107.     if(--nready<=0)
  108.      break;  /* 没有可读的描述符了 */
  109.    }
  110.   }
  111.  }
  112. }
  113. /*-----------------------------------------*/
  114. /* png图片生成函数 */
  115. int
  116. getpng(char *filename,char *string,int strlen)
  117. {
  118.  int back,word,front,len,sx,sy,i;
  119.  char *str;
  120.  gdImagePtr newimg;
  121.  FILE *pngfp;
  122.  str=string;
  123.  len=strlen;
  124.  sx=10+len*9;
  125.  sy=20;
  126.  newimg=gdImageCreate(sx,sy); /* 创建一变量存放空白图像,像素sx*sy */
  127.  pngfp=fopen(filename,"wb");
  128.  back=gdImageColorAllocate(newimg,0,255,128); /* 匹配背景的颜色 */
  129.  word=gdImageColorAllocate(newimg,255,0,128); /* 匹配字符的颜色 */
  130.  front=gdImageColorAllocate(newimg,255,64,128); /* 匹配干扰线的颜色 */
  131.  gdImageFill(newimg,0,0,back);   /* 为图像填充以上颜色 */
  132.  gdImageString(newimg,gdFontGiant,5,1,str,word); /* 生成字符图象 */
  133.  for(i=0;i<len;(i=i+2))    /* 生成干扰线 */
  134.   gdImageLine(newimg,(5+i*9),0,(23+i*9),20,front);
  135.  gdImagePng(newimg,pngfp);   /* 创建PNG图像 */
  136.  gdImageDestroy(newimg);    /* 破坏图像流以释放内存 */
  137.  fclose(pngfp);
  138.  return;
  139. }
  140. /*---------------------------------------------*/
  141. /* 发送文件到客户端 */
  142. void
  143. sendFile(int sock, char *filename)
  144. {
  145.  char pngbuf[65535],clenth[32],*sendDate;
  146.  char sendbuf[8192]="HTTP/1.0 200 OK/nServer: mypngserver (FreeBSD)/nMime-Version:
  147. 1.0/nDate: ";
  148.  int n;
  149.  time_t tp;
  150.  FILE *fp;
  151.  fp=fopen(filename,"r");
  152.  n=fread(&pngbuf,sizeof(char),65535,fp); /* 以二进制结构读取PNG图片文件 */
  153.  tp=time(NULL);
  154.  sendDate=ctime(&tp);  /* 生成当前时间 */
  155.  strcat(sendbuf,sendDate);
  156.  strcat(sendbuf,"Content-Type: image/png/nContent-Length: ");
  157.  sprintf(clenth,"%d/n",n); /* 当前PNG图片的大小 */
  158.  strcat(sendbuf,clenth);
  159.  strcat(sendbuf,"Connection: close/n/n");
  160.  send(sock,sendbuf,strlen(sendbuf),0); /* 发送服务器的Respond */
  161.  write(sock,pngbuf,n);   /* 发送PNG图片 */
  162.  fclose(fp);
  163. }
  164. /*-----------------------------------------------------*/
  165. /* daemon进程初始化函数 */
  166. int
  167. daemon_init(const char *pname)
  168. {
  169.  int i;
  170.  pid_t pid;
  171.  if((pid=fork())!=0)
  172.   exit(0);
  173.  setsid();  /* 进程成为会话首进程,不再有控制终端 */
  174.  signal(SIGHUP,SIG_IGN); /* 忽略SIGHUP信号并再次fork */
  175.  if((pid=fork())!=0)
  176.   exit(0);
  177.  chdir("/");  /* 改变工作目录 */
  178.  umask(0);  /* 清文件创建屏蔽字 */
  179.  for(i=0;i<64;i++) /* 关闭所有打开的文件描述符 */
  180.   close(i);
  181.  openlog(pname,LOG_PID,0);
  182. }
  183. /*----------------------------------------------------------*/
  184. /* daemon进程出错处理的两个函数 */
  185. void
  186. log_sys(const char *fmt, ...)
  187. {
  188.  va_list ap;
  189.  va_start(ap,fmt);
  190.  log_doit(1,LOG_ERR,fmt,ap);
  191.  va_end(ap);
  192.  exit(2);
  193. }
  194. static void
  195. log_doit(int errnoflag, int priority, const char *fmt, va_list ap)
  196. {
  197.  int errno_save;
  198.  char buf[BUFFSIZE];
  199.  errno_save=errno;
  200.  vsprintf(buf,fmt,ap);
  201.  if(errnoflag)
  202.   sprintf(buf+strlen(buf),":%s",strerror(errno_save));
  203.  strcat(buf,"/n");
  204.  syslog(priority,buf);
  205.  return;
  206. }
  207. /* end all*/

 

转自http://blog.youkuaiyun.com/hustxxb/archive/2005/01/08/244618.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值