/** SQLET WebServer 测试 http://www.sqlet.com mail:199909@gmail.com **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_THREAD 1024 #define MAX_MUTEX 10 #define QUEUE_BLOCK 1 #define LOAD_PAGE_BLOCK 2 #define READ_TIMEOUT 3000 // 3秒 #define BUF_SIZE 2048 #define MAX_PARAM_NAME 16 #define MAX_PARAM_VALUE 64 #define MAX_CMD_LEN 12 typedef struct PARAM_NODE{ char name[MAX_PARAM_NAME]; char value[MAX_PARAM_VALUE]; struct PARAM_NODE *next; }PARAM_NODE; pthread_t threadML[MAX_THREAD]; sem_t threadSem[MAX_THREAD]; int threadFdc[MAX_THREAD]; char * mime_head ="HTTP/1.0 %d %s\r\nServer: %s\r\nContent-type: %s\r\nConnection: Close\r\n\r\n"; char * ptrHomePageBuf = ( char *)0; int iHomePageBufLen = 0 ; char * fileHomePage = "index.html"; typedef void* (*StartFun) (void *); void homePage(int,PARAM_NODE *); void searchPage(int,PARAM_NODE *); void errorPage(int ,char *); struct listCommand { char command[MAX_CMD_LEN+1]; void (*cmdFun) ( int,PARAM_NODE * ); }LIST_COMMAND [] = { {"/" ,homePage}, {"/s" ,searchPage}, {"/index.html" ,homePage}, {"/index.htm" ,homePage}, {"\0", NULL} }; int startThread (StartFun run, int iThreadNum); int stopThread(int iThreadNum); void *searcherThread (void *pthreadNum); int startWebServer (int iHttpPort,int iThreadNum) ; inline int hexVal(char c) { if (c >= '0' && c <= '9') return c - '0'; else if (c >= 'a' && c <= 'f') return c - 'a' + 10; else if (c >= 'A' && c <= 'F') return c - 'A' + 10; else return 0; } inline void strTrim(char str[]) { int firstchar=0; int endpos=0; int i; int firstpos=0; for(i=0;str[i]!='\0';i++){ if(str[i]==' ' || str[i] == '\r' || str [i] == '\n' || str [i]=='\t'){ if(firstchar==0) firstpos++; } else{ endpos=i; firstchar=1; } } for(i=firstpos;i<=endpos;i++) str[i-firstpos]=str[i]; str[i-firstpos]='\0'; } void urlUnescape(char *strUrl) { int i = 0; int j = 0; while (strUrl[i] != 0) { if ( strUrl[i] == '+' ) strUrl[i] = ' ' ; /* 空格 */ if ((strUrl[i] == '%') && (strUrl[i+1] != 0) && (strUrl[i+2] != 0)) { strUrl[j] = 16 * hexVal(strUrl[i+1]) + hexVal(strUrl[i+2]); i += 3; }else { strUrl[j] = strUrl[i]; i++; } j++; } strUrl[j] = 0; } int splitQuery(char *strUrl, char *strName, char *strValue) { int iPos; int i, j,len=0; i=0; while ((strUrl[i] != '=') && (strUrl[i] != 0) && (strUrl[i] != ' ')) { i++; len++; } if (strUrl[i] == '=') { iPos = i; for (i=0,j=0; iname,name); strcpy(head->value,value); strQuery = strQuery + len + 1; head->next= queryParamList(strQuery); return head; } } void errorPage(int fdc,char *strMessage) { char bufSocket[BUF_SIZE +1]; sprintf(bufSocket, mime_head, 200, "OK", "SQLET_Searcher","text/html; charset=gb2312"); sprintf(bufSocket,"sqlet

%s

",strMessage); write(fdc,bufSocket,strlen(bufSocket)); } void homePage(int fdc ,PARAM_NODE * param) { write(fdc,ptrHomePageBuf,iHomePageBufLen); } void searchPage(int fdc,PARAM_NODE * param) { //在这里执行搜索 write(fdc,ptrHomePageBuf,iHomePageBufLen); } int loadFirstPage(int fdc) { //在浏览上发一个命令,server自动把首页的文件载到(更新)内存 ,程序一起动的也载到内存 struct stat ast; int handle; char *filebuf , buf[128]; if ((handle = open(fileHomePage, O_RDONLY)) < 0) { sprintf(buf,"首页文件(%s)没有找到!",fileHomePage); if ( fdc < 1 ) return -1; }else { fstat(handle, &ast); if ((filebuf = (char *)malloc(ast.st_size + 1))==NULL) if ( fdc < 1 ) return -1; if ((ast.st_size = read(handle, filebuf, ast.st_size)) < 0) { sprintf(buf,"读文件(%s)出错!", fileHomePage); free(filebuf); filebuf = ( char *)0; } else { filebuf[ast.st_size] = '\0'; if ( ptrHomePageBuf != ( char *)0) free(ptrHomePageBuf); ptrHomePageBuf = &filebuf[0]; iHomePageBufLen = ast.st_size ; sprintf(buf,"首页文件(%s)成功加载到内存!", fileHomePage); } close(handle); } if ( fdc > 0 ) errorPage(fdc,buf); else printf("%s\n",buf); //在程序启动时加载 return 0; } inline int setnonblock(int fdc,int to) { struct timeval timeout; timeout.tv_sec = to/1000; timeout.tv_usec=0; if (setsockopt(fdc, SOL_SOCKET, SO_RCVTIMEO,(char*) &timeout, sizeof(timeout))) return 0; return 1; } void *searcherThread (void *pthreadNum) { int i , nThread , fdc ,condition = 1 ,size = 0,lineStartPos = 0; char bufSocket[BUF_SIZE + 1]; char strKeyWord[32],strCharset[16] ,*ptrUrl, *ptrQuery ; int iPageNum ; PARAM_NODE *paramList , *ptmp; long tStart =0 , tEnd = 0 ; nThread = ( int ) pthreadNum ; while ( condition ) { sem_wait(&threadSem[nThread]); fdc = threadFdc[nThread]; if ( fdc < 0 ) continue; tStart = currentTimeMillis(); bzero((char *) bufSocket, sizeof(bufSocket)); // setnonblock(fdc, READ_TIMEOUT); size = read(fdc, bufSocket, BUF_SIZE); if ( size < 0) size = 0 ; bufSocket[size] = '\0'; //内容不能超过BUF_SIZE if ( ( size == BUF_SIZE) || (bufSocket[0] != 'G' ) || (bufSocket[1] != 'E') || (bufSocket[2] != 'T')) { errorPage(fdc,"请求出错!"); threadFdc[nThread] = -1 ; close(fdc); continue; } i = 4 ; ptrUrl = &bufSocket[i]; ptrQuery = ( char *)0; while ( bufSocket[i] != ' ' && bufSocket[i] != '\t' && bufSocket[i] != '\n' && bufSocket[i] != '\r' && bufSocket[i] != '\0') { if ( bufSocket[i] == '?' ){ bufSocket[i] = '\0'; if ( bufSocket[i+1] != '\0') ptrQuery = &bufSocket[i+1]; } i ++ ; } bufSocket[i] = '\0'; i ++ ; lineStartPos = i ; for ( i = lineStartPos; i < size ; i ++ ) { if ( bufSocket[i] == '\r' && bufSocket[i+1] == '\n' ) { if ( strncasecmp( &bufSocket[lineStartPos],"Host:",5) == 0 ) { bufSocket[i] = '\0'; // printf("found host |%s|\n",&bufSocket[lineStartPos]+6); }else if ( strncasecmp( &bufSocket[lineStartPos],"Accept-Language:",16) == 0) { bufSocket[i] = '\0'; // printf("found language|%s|\n",&bufSocket[lineStartPos+17]); } i += 2 ; lineStartPos = i ; } }// end for i paramList = queryParamList (ptrQuery); i = 0 ; while ( LIST_COMMAND[i].command[0] != '\0') { if ( strcmp(LIST_COMMAND[i].command , ptrUrl ) == 0 ) { LIST_COMMAND[i].cmdFun(fdc , paramList); break ; } i ++ ; } if ( LIST_COMMAND[i].command[0] == '\0' ) { errorPage(fdc,"请求出错,找不到指令!"); } while( paramList !=NULL ) { printf("%s --------%s\n",paramList->name,paramList->value); ptmp = paramList; paramList = paramList -> next; free(ptmp); ptmp = ( PARAM_NODE *)NULL; } tEnd = currentTimeMillis(); printf("THREADNUM:%d|time:%ldms|cmd:%s|query:%s \n",(int)pthreadNum,(tEnd - tStart ),ptrUrl,ptrQuery); threadFdc[nThread] = -1 ; close(fdc); } // end while ( condition) } int startWebServer (int iHttpPort,int iThreadNum) { int fds , fdc , i = 0 ; int iAllowReuse = 1; struct sockaddr_in serverAddr , clientAddr; int iClientLen = sizeof(serverAddr); bzero((char *) &serverAddr, sizeof(struct sockaddr_in)); serverAddr.sin_addr.s_addr = INADDR_ANY; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(iHttpPort); if ((fds = socket(AF_INET, SOCK_STREAM, 0)) == -1 || setsockopt(fds, SOL_SOCKET, SO_REUSEADDR, (char*)&iAllowReuse, sizeof(iAllowReuse)) || bind(fds, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) != 0 || listen(fds, 8) != 0) { printf("Unable to start the WebServer ( errorno:%d ) \n",errno); return -1; } i = 0 ; if ( startThread(searcherThread,iThreadNum) < 0) return -1; while ( 1 ) { printf("accept.....\n"); fdc = accept(fds, (struct sockaddr *) &clientAddr, (int *)&iClientLen); if (fdc == -1) { printf("accept web server error!...\n"); } /** todo:超过最大线程数,自动建 **/ while ( threadFdc[i] >= 0) { i ++ ; if ( i >= iThreadNum ){ //队列已满,等待 usleep(500); i = 0 ; } } threadFdc[i] = fdc ; sem_post(&threadSem[i]); i ++ ; if ( i >= iThreadNum ) i = 0 ; } // end while return 0; } int startThread (StartFun run, int iThreadNum) { int i ; pthread_attr_t attr; for ( i = 0 ; i < iThreadNum ; i ++ ) { printf("thread create %d\n",i); sem_init(&threadSem[i],0,0); threadFdc[i] = -1; if (pthread_attr_init(&attr) != 0 || pthread_create(&threadML[i], &attr, run, (void *)i) != 0 || pthread_attr_destroy(&attr) != 0 // || pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) != 0 || pthread_detach(threadML[i]) != 0) // if ( pthread_create(&threadML[i], NULL, run, (void *)i) != 0) { printf("创建线程错误:\r\n\r\n"); return -1; } // end if }// end for i return 0; } int stopThread(int iThreadNum) { int i; for(i=0; i < iThreadNum; i++) { if(threadML[i] !=0 ) pthread_join(threadML[i],NULL); // pthread_exit(&i); } } void sigdie(int a) { printf("\r\n\r\nCaught signal n.%d\r\n\r\n",a); if(a==15) { printf("\r\n退出...\r\n"); exit(0); } // stopThread(int iThreadNum) } int main(void) { // signal(SIGINT, sigdie); // signal(SIGTERM, sigdie); if (loadFirstPage( -1 ) < 0 ) { printf("找不到默认的首页文件...\n"); return -1; } startWebServer(80,200); }