- 本程序是一个提供特殊服务的Web Server。该程序是一个Daemon程序,用单进程+I/O多路转换(select)的方式接收Http的Get请求,请求中是一个字符串(可以是数字或者字母),返回一个PNG格式的图片,整个过程符合Http 1.0协议。
- 本程序类似于网站上常用的生成“验证码”的程序。
- 本程序在FreeBSD环境下开发完成,并可同时在FreeBSD和Windows (Cygwin)下编译运行。FreeBSD环境安装有gd-1.8.4库,Cygwin环境安装有libpng-1.2.8和gd-2.0.33库,用于生成PNG图片。
- 整个程序用C语言完成,源代码如下:
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <sys/time.h>
- #include <signal.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <time.h>
- #include <syslog.h>
- #include <errno.h>
- #include <string.h>
- #include <stdarg.h>
- #include <unistd.h>
- #include <gd.h>
- #include <gdfontg.h>
- #define MAXCLIENT 1024
- #define BUFFSIZE 4096
- int daemon_init(const char *);
- int getpng(char *,char *,int);
- void sendFile(int, char *);
- void log_sys(const char *, ...);
- static void log_doit(int, int, const char *, va_list ap);
- int
- main(int argc, char **argv)
- {
- int i,maxi,maxfd,listenfd,connfd,hfd,nready,client[MAXCLIENT];
- char *p,*pp, recvbuf[BUFFSIZE];
- ssize_t recvlen;
- fd_set rset, allset;
- struct sockaddr_in servaddr;
- daemon_init(argv[0]);
- listenfd=socket(AF_INET, SOCK_STREAM, 0);
- bzero(&servaddr, sizeof(servaddr));
- servaddr.sin_family =AF_INET;
- servaddr.sin_addr.s_addr =htonl(INADDR_ANY);
- servaddr.sin_port =htons(80);
- bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
- listen(listenfd,5);
- maxfd=listenfd;
- maxi=-1;
- for(i=0;i<MAXCLIENT;i++)
- client[i]=-1;
- FD_ZERO(&allset);
- FD_SET(listenfd, &allset);
- for(;;){
- rset=allset;
- nready=select(maxfd+1, &rset, NULL, NULL, NULL);
- if(FD_ISSET(listenfd, &rset)){
- connfd=accept(listenfd,(struct sockaddr *)NULL,NULL);
- for(i=0;i<FD_SETSIZE;i++)
- if(client[i]<0){
- client[i]=connfd;
- break;
- }
- if(i==MAXCLIENT)
- log_sys("connection overflow");
- FD_SET(connfd, &allset);
- if(connfd>maxfd)
- maxfd=connfd;
- if(i>maxi)
- maxi=i;
- if(--nready<=0)
- continue;
- }
- for(i=0;i<=maxi;i++){
- if((hfd=client[i])<0)
- continue;
- if(FD_ISSET(hfd, &rset)){
- if((recvlen=recv(hfd,recvbuf,sizeof(recvbuf),0))==0){
- close(hfd);
- FD_CLR(hfd, &allset);
- client[i]=-1;
- }else
- if(strncmp(recvbuf,"GET",3)==0){
- p=strchr(recvbuf+3,'/');
- if(p!=0){
- pp=strstr(recvbuf+3,"HTTP/1.");
- if(pp!=0){
- p++;
- pp--;
- *pp='/0';
- getpng
- ("/tmp/pass.png",p,strlen(p));
- sendFile
- (hfd,"/tmp/pass.png");
- close(hfd);
- FD_CLR(hfd, &allset);
- client[i]=-1;
- }
- }
- }
- if(--nready<=0)
- break;
- }
- }
- }
- }
- int
- getpng(char *filename,char *string,int strlen)
- {
- int back,word,front,len,sx,sy,i;
- char *str;
- gdImagePtr newimg;
- FILE *pngfp;
- str=string;
- len=strlen;
- sx=10+len*9;
- sy=20;
- newimg=gdImageCreate(sx,sy);
- pngfp=fopen(filename,"wb");
- back=gdImageColorAllocate(newimg,0,255,128);
- word=gdImageColorAllocate(newimg,255,0,128);
- front=gdImageColorAllocate(newimg,255,64,128);
- gdImageFill(newimg,0,0,back);
- gdImageString(newimg,gdFontGiant,5,1,str,word);
- for(i=0;i<len;(i=i+2))
- gdImageLine(newimg,(5+i*9),0,(23+i*9),20,front);
- gdImagePng(newimg,pngfp);
- gdImageDestroy(newimg);
- fclose(pngfp);
- return;
- }
- void
- sendFile(int sock, char *filename)
- {
- char pngbuf[65535],clenth[32],*sendDate;
- char sendbuf[8192]="HTTP/1.0 200 OK/nServer: mypngserver (FreeBSD)/nMime-Version:
- 1.0/nDate: ";
- int n;
- time_t tp;
- FILE *fp;
- fp=fopen(filename,"r");
- n=fread(&pngbuf,sizeof(char),65535,fp);
- tp=time(NULL);
- sendDate=ctime(&tp);
- strcat(sendbuf,sendDate);
- strcat(sendbuf,"Content-Type: image/png/nContent-Length: ");
- sprintf(clenth,"%d/n",n);
- strcat(sendbuf,clenth);
- strcat(sendbuf,"Connection: close/n/n");
- send(sock,sendbuf,strlen(sendbuf),0);
- write(sock,pngbuf,n);
- fclose(fp);
- }
- int
- daemon_init(const char *pname)
- {
- int i;
- pid_t pid;
- if((pid=fork())!=0)
- exit(0);
- setsid();
- signal(SIGHUP,SIG_IGN);
- if((pid=fork())!=0)
- exit(0);
- chdir("/");
- umask(0);
- for(i=0;i<64;i++)
- close(i);
- openlog(pname,LOG_PID,0);
- }
- void
- log_sys(const char *fmt, ...)
- {
- va_list ap;
- va_start(ap,fmt);
- log_doit(1,LOG_ERR,fmt,ap);
- va_end(ap);
- exit(2);
- }
- static void
- log_doit(int errnoflag, int priority, const char *fmt, va_list ap)
- {
- int errno_save;
- char buf[BUFFSIZE];
- errno_save=errno;
- vsprintf(buf,fmt,ap);
- if(errnoflag)
- sprintf(buf+strlen(buf),":%s",strerror(errno_save));
- strcat(buf,"/n");
- syslog(priority,buf);
- return;
- }
转自http://blog.csdn.net/hustxxb/archive/2005/01/08/244618.aspx