📄 soso1.c
字号:
/**
SQLET WebServer 测试
http://www.sqlet.com
mail:199909@gmail.com
**/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <malloc.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <semaphore.h>
#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; i<iPos; i++,j++) {
if (i == 0 && strUrl [0] == '&')
{
strName[j] = strUrl[i+1];
i++;
}else strName[j] = strUrl[i];
}
strName[j] = 0;
i = iPos + 1;
j = 0;
while (strUrl[i] != 0 && strUrl[i] != ' ' && strUrl[i] != '&') {
strValue[j] = strUrl[i];
i++;
j++;
len++;
}
strValue[j] = '\0';
return len;
}
return 0;
}
inline long currentTimeMillis()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec*1000L+tv.tv_usec/1000L;
}
PARAM_NODE *queryParamList(char *strQuery)
{
PARAM_NODE *head;
int len = 0;
char name[MAX_PARAM_NAME],value[MAX_PARAM_VALUE];
if(strQuery==NULL)
return (PARAM_NODE *)NULL;
else{
len=splitQuery(strQuery,name,value);
if(len==0)
return (PARAM_NODE *)NULL;
urlUnescape(name);
urlUnescape(value);
head=(PARAM_NODE *) malloc (sizeof (PARAM_NODE));
if ( head == (PARAM_NODE *) NULL)
return (PARAM_NODE *) NULL;
strTrim(name);
strTrim(value);
strcpy(head->name,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,"<html><head><title>sqlet</title></head><body><h1>%s</h1></body></html>",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);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -