myhttp脚本文件
#!/bin/sh WHOAMI=`whoami` PID=`ps -u $WHOAMI | grep myhttpd | awk '{print $1}'` if (test "$#" = 0) then echo "Usage: $0 [stop] [start] [status]" exit 0 fi if (test "$1" = "start") then if (test "$PID" = "") then ./myhttpd 8080 else echo "myhttp is running" fi exit 0 fi if (test "$1" = "stop") then if (test "$PID" != "") then kill -s 2 $PID fi exit 0 fi if (test "$1" = "status") then if (test "$PID" = "") then echo "myhttp is not run" else echo "myhttp is running" fi exit 0 fi echo "Usage: $0 [stop] [start] [status]"
makefile
.SUFFIXES: .c .o CC=gcc PROC=proc ORACLE_HOME=/opt/oracle/product/11.2.0 ORAFLAGS1=/usr/include/linux ORAFLAGS2=/usr/lib/gcc/i686-redhat-linux/4.4.4/include PROCSRCS=myoracle.pc DBSRCS=$(PROCSRCS:.pc=.c) SRCS=server.c pub.c work.c $(DBSRCS) OBJS=$(SRCS:.c=.o) EXEC=myhttpd ORCFLAGS1=-L${ORACLE_HOME}/lib ORCFLAGS2=-lclntsh all: $(OBJS) $(CC) -o $(EXEC) $(OBJS) -lpthread $(ORCFLAGS1) $(ORCFLAGS2) @echo '-------------ok--------------' .c.o: $(DBSRCS) $(CC) -Wall -g -o $@ -c $< $(DBSRCS): ${PROC} INAME=$(PROCSRCS) INCLUDE=$(ORAFLAGS1) INCLUDE=$(ORAFLAGS2) CPOOL=YES MODE=ANSI CODE=ANSI_C PARSE=PARTIAL THREADS=YES ONAME=$(DBSRCS) clean: rm -f $(OBJS) rm -f $(DBSRCS) rm -f core*
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <signal.h> #include "pub.h" #include "myoracle.h" int main(int arg, char *args[]) { if (arg < 2)//如果没有参数,main函数返回 { printf("usage:myserver port\n"); return EXIT_FAILURE; } int iport = atoi(args[1]);//将第一个参数转化为整数 if (iport == 0) { printf("port %d is invalid\n", iport); return EXIT_FAILURE; } if (sql_connect("dbuser1", "dbuser1", "orcl") == -1)//连接到数据库 return EXIT_FAILURE; int st = socket_create(iport);//建立socket if (st == 0) return EXIT_FAILURE; printf("myhttp is begin\n"); setdaemon();//设置进程为daemon状态 signal1(SIGINT, catch_Signal); //捕捉SIGINT信号 socket_accept(st); close(st); sql_disconnect(); printf("myhttp is end\n"); return EXIT_SUCCESS; }
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <pthread.h> #include <sys/socket.h> #include <netinet/in.h> #include "work.h" #include "pub.h" #include "myoracle.h" //8192是8k #define BUFSIZE 8192 #define HEAD "HTTP/1.0 200 OK\nContent-Type: %s\nTransfer-Encoding: chunked\nConnection: Keep-Alive\nAccept-Ranges:bytes\nContent-Length:%d\n\n" #define TAIL "\n\n" #define EXEC "s?wd=" void gethttpcommand(const char *sHTTPMsg, char *command) //从http请求中读出GET后面的命令行 { int i; int istart = 0; int iend = 0; for (i = 0; i < strlen(sHTTPMsg); i++) { if ((sHTTPMsg[i] == ' ') && (istart == 0))//第一个空格 { istart = i + 2; } else { if (sHTTPMsg[i] == ' ')//第二个空格 { iend = i; break;//得到位置了,退出循环 } } } strncpy(command, &sHTTPMsg[istart], (iend - istart)); } int gettempletcontent(char *buf) //得到模板文件templet.html的内容 { struct stat t; memset(&t, 0, sizeof(t)); FILE *fd = fopen("templet.html", "rb"); if (fd != NULL) { stat("templet.html", &t); fread(buf, t.st_size, 1, fd); return t.st_size; } else { printf("open %s failed %s\n", "templet.html", strerror(errno)); return 0; } } int getdynamicccontent(const char *query, char **buf) //动态设置http请求内容,query为条件,buf为动态内容 { char templetcontent[1024]; memset(templetcontent, 0, sizeof(templetcontent)); if (gettempletcontent(templetcontent) == 0) return 0; *buf = malloc(BUFSIZE); char *body = NULL; if (query_result(query, &body) == -1) { body = malloc(128); memset(body, 0, 128); strcpy(body, "抱歉,没有查询结果"); } sprintf(*buf, templetcontent, query, body); free(body); return strlen(*buf); } int make_http_content(const char *command, char **buf) //根据get提供的文件名,生成静态http reponse消息内容 { char *contentbuf = NULL; int icontentlen = 0; if (command[0] == 0) //GET请求后面为空,得到默认页面内容图 { icontentlen = getfilecontent("default.html", &contentbuf); } else { if (strncmp(command, EXEC, strlen(EXEC)) == 0) //GET请求后面为s?wd= { char query[1024]; memset(query, 0, sizeof(query)); httpstr2stdstr(&command[strlen(EXEC)], query); //得到s?wd=字符串后面的转义字符内容 icontentlen = getdynamicccontent(query, &contentbuf); } else { icontentlen = getfilecontent(command, &contentbuf);//动态设置http请求内容,query为条件,buf为动态内容 } } if (icontentlen > 0)//组成一个http的回复 { char headbuf[1024]; memset(headbuf, 0, sizeof(headbuf)); sprintf(headbuf, HEAD, getfiletype(command), icontentlen); //设置消息头 int iheadlen = strlen(headbuf);//得到消息头长度 int itaillen = strlen(TAIL);//得到消息尾长度 int isumlen = iheadlen + icontentlen + itaillen;//得到消息总长度 *buf = malloc(isumlen);//根据消息总长度,动态分配内存 char *tmp = *buf; memcpy(tmp, headbuf, iheadlen); //安装消息头 memcpy(&tmp[iheadlen], contentbuf, icontentlen); //安装消息体 memcpy(&tmp[iheadlen + icontentlen], TAIL, itaillen); //安装消息尾 printf("headbuf:\n%s", headbuf); if (contentbuf) free(contentbuf); return isumlen;//返回消息总长度 } else { return 0; } } void *socket_contr(void *arg)//线程入口函数 { printf("thread is begin\n"); int st = *(int *) arg;//得到来自client端的socket free((int *) arg); char buf[BUFSIZE]; memset(buf, 0, sizeof(buf)); int rc = recv(st, buf, sizeof(buf), 0);//接收来自client端socket的消息 if (rc <= 0) { printf("recv failed %s\n", strerror(errno)); } else { printf("recv:\n%s", buf); char command[1024]; memset(command, 0, sizeof(command)); gethttpcommand(buf, command); //得到http 请求中 GET后面的字符串 char *content = NULL; int ilen = make_http_content(command, &content);//根据用户在GET中的请求,生成相应的回复内容 if (ilen > 0) { send(st, content, ilen, 0);//将回复的内容发送给client端socket free(content); } } close(st);//关闭client端socket printf("thread_is end\n"); //count--; return NULL; }
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <pthread.h> #include <sys/socket.h> #include <netinet/in.h> #include <signal.h> #include <fcntl.h> #include "work.h" #include "pub.h" void setdaemon() { pid_t pid, sid; pid = fork(); if (pid < 0) { printf("fork failed %s\n", strerror(errno)); exit (EXIT_FAILURE); ; } if (pid > 0) { exit (EXIT_SUCCESS); } if ((sid = setsid()) < 0) { printf("setsid failed %s\n", strerror(errno)); exit (EXIT_FAILURE); } /* if (chdir("/") < 0) { printf("chdir failed %s\n", strerror(errno)); exit(EXIT_FAILURE); } umask(0); close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); */ } void catch_Signal(int Sign) { switch (Sign) { case SIGINT: printf("signal SIGINT\n"); break; } } int signal1(int signo, void (*func)(int)) { struct sigaction act, oact; act.sa_handler = func; sigemptyset(&act.sa_mask); act.sa_flags = 0; return sigaction(signo, &act, &oact); } int hex2dec(const char hex) //将16进制的字符转化为十进制的整数,例如:'a'转化为整数10,‘B’转化为整数11 { switch (hex) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'a': return 10; case 'A': return 10; case 'b': return 11; case 'B': return 11; case 'c': return 12; case 'C': return 12; case 'd': return 13; case 'D': return 13; case 'e': return 14; case 'E': return 14; case 'f': return 15; case 'F': return 15; default: return -1; } } //将两位16进制的字符串转化为十进制的unsigned char,例如:'10'转化为16,‘1A'转化为17 unsigned char hexstr2dec(const char *hex) { return hex2dec(hex[0]) * 16 + hex2dec(hex[1]); } //将HTTP GET请求中的转义符号转化为标准字符,注意,空格被转义为'+'号 void httpstr2stdstr(const char *httpstr, char *stdstr) { int index = 0; int i; for (i = 0; i < strlen(httpstr); i++) { if (httpstr[i] == '%') { stdstr[index] = hexstr2dec(&httpstr[i + 1]); i += 2; } else { stdstr[index] = httpstr[i]; } index++; } } const char *getfiletype(const char *filename) //根据扩展名返回文件类型描述 { ////////////得到文件扩展名/////////////////// int len = strlen(filename); int i; char sExt[32]; memset(sExt, 0, sizeof(sExt)); for (i = 0; i < len; i++) { if (filename[i] == '.') { strncpy(sExt, &filename[i + 1], sizeof(sExt)); break; } } ////////根据扩展名返回相应描述/////////////////// if (strncmp(sExt, "bmp", 3) == 0) return "image/bmp"; if (strncmp(sExt, "gif", 3) == 0) return "image/gif"; if (strncmp(sExt, "ico", 3) == 0) return "image/x-icon"; if (strncmp(sExt, "jpg", 3) == 0) return "image/jpeg"; if (strncmp(sExt, "avi", 3) == 0) return "video/avi"; if (strncmp(sExt, "css", 3) == 0) return "text/css"; if (strncmp(sExt, "dll", 3) == 0) return "application/x-msdownload"; if (strncmp(sExt, "exe", 3) == 0) return "application/x-msdownload"; if (strncmp(sExt, "dtd", 3) == 0) return "text/xml"; if (strncmp(sExt, "mp3", 3) == 0) return "audio/mp3"; if (strncmp(sExt, "mpg", 3) == 0) return "video/mpg"; if (strncmp(sExt, "png", 3) == 0) return "image/png"; if (strncmp(sExt, "ppt", 3) == 0) return "application/vnd.ms-powerpoint"; if (strncmp(sExt, "xls", 3) == 0) return "application/vnd.ms-excel"; if (strncmp(sExt, "doc", 3) == 0) return "application/msword"; if (strncmp(sExt, "mp4", 3) == 0) return "video/mpeg4"; if (strncmp(sExt, "ppt", 3) == 0) return "application/x-ppt"; if (strncmp(sExt, "wma", 3) == 0) return "audio/x-ms-wma"; if (strncmp(sExt, "wmv", 3) == 0) return "video/x-ms-wmv"; return "text/html"; } int getfilecontent(const char *filename, char **buf) //得到文件内容 {//如果一个函数内部要给参数分配空间,那么这个参数必须是二级指针。 struct stat t; memset(&t, 0, sizeof(t)); FILE *fd = fopen(filename, "rb");//从只读方式打开参数filename指定的文件 if (fd != NULL) { stat(filename, &t); *buf = malloc(t.st_size);//根据文件大小,动态分配内存buf fread(*buf, t.st_size, 1, fd);//将文件读取到buf fclose(fd); return t.st_size; } else { printf("open %s failed %s\n", filename, strerror(errno)); return 0; } } int socket_create(int port)//根据参数port,建立server端socket { int st = socket(AF_INET, SOCK_STREAM, 0);//建立TCP的socket描述符 if (st == -1) { printf("socket failed %s\n", strerror(errno)); return 0; } int on = 1; if (setsockopt(st, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { printf("setsockopt failed %s\n", strerror(errno)); return 0; } struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(st, (struct sockaddr *) &addr, sizeof(addr)) == -1) { printf("bind failed %s\n", strerror(errno)); return 0; } if (listen(st, 100) == -1) { printf("listen failed %s\n", strerror(errno)); return 0; } printf("listen %d success\n", port); return st;//返回listen的socket描述符 } void sockaddr_toa(const struct sockaddr_in *addr, char *IPAddr)//将struct sockaddr_in转化为IP地址字符串 { unsigned char *p = (unsigned char *)&(addr->sin_addr.s_addr); sprintf(IPAddr, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]); } void socket_accept(int st) { pthread_t thr_d; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//设置线程为可分离状态 int client_st = 0; struct sockaddr_in client_addr; socklen_t len = sizeof(client_addr); while (1)//循环执行accept { memset(&client_addr, 0, sizeof(client_addr)); //accept函数阻塞,知道有client端连接到达,或者accept错误返回 client_st = accept(st, (struct sockaddr *)&client_addr, &len); /* //加一个计数器,count++; if(count > 200)//如果客户端连接个数为200个上限值 { close(client); continue; } */ if (client_st == -1) { printf("accept failed %s\n", strerror(errno)); break;//accept错误,循环break } else { char sIP[32]; memset(sIP, 0, sizeof(sIP)); sockaddr_toa(&client_addr, sIP); printf("accept by %s\n", sIP); int *tmp = malloc(sizeof(int)); *tmp = client_st; { //将来自client端的socket做为参数,启动一个可分离线程 pthread_create(&thr_d, &attr, socket_contr, tmp); } } } pthread_attr_destroy(&attr); }
#include <stdio.h> #include <stdlib.h> #include <string.h> EXEC SQL BEGIN DECLARE SECTION; sql_context pContext; long SQLCODE; EXEC SQL END DECLARE SECTION; extern void sqlglmt(void*, char*, size_t*, size_t* ); void sql_error()//定义一个错误安装函数 { char sErrorString[512]; size_t tMessageSize = 0; size_t tErrorSize = sizeof(sErrorString); memset(sErrorString, 0, sizeof(sErrorString)); sqlglmt(pContext, sErrorString, &tErrorSize, &tMessageSize); sErrorString[tMessageSize] = 0; printf("%s\n", sErrorString); } void sql_init()//初始化oracle { SQLCODE = 0; pContext = NULL; EXEC SQL ENABLE THREADS;//标明可以在线程中使用 EXEC SQL CONTEXT ALLOCATE :pContext;//为pContext分配资源 EXEC SQL CONTEXT USE :pContext;//使用m_pContext } int sql_free() { SQLCODE = 0; EXEC SQL CONTEXT FREE :pContext; if (SQLCODE != 0) { sql_error(); return -1; }else { return 0; } } int sql_connect(const char *User, const char *Password, const char *DBName) { sql_init(); EXEC SQL BEGIN DECLARE SECTION; const char *sUser; const char *sPassword; const char *sServer; EXEC SQL END DECLARE SECTION; SQLCODE = 0; sUser = User; sPassword = Password; sServer = DBName; EXEC SQL CONNECT :sUser IDENTIFIED BY :sPassword USING :sServer;//连接到oracle if (SQLCODE != 0) { sql_error();//连接失败,打印错误原因 return -1; }else { return 0; } } int sql_disconnect()//断开数据库连接 { SQLCODE = 0; EXEC SQL ROLLBACK WORK RELEASE; return sql_free(); } void addurl(const char *url, const char *name, const char *description, char **buf) //向动态消息体中添加一个url链接 { char content[1024]; memset(content, 0, sizeof(content)); sprintf(content, "<a href=\"http://%s\">%s</a></br>%s%s</br></br>", url, name, name, description);//格式化字符串 if (*buf != NULL)//addurl函数已经调用过了,所以buf的值不等于NULL { int buflen = strlen(*buf);//得到buf中字符串的长度 int contentlen = strlen(content);//得到conntent中字符串的长度 int sumlen = buflen + contentlen;//得到buf中字符串和content中字符串的长度之和 char *tmp = malloc(sumlen + 1);//分配一个新的临时缓冲区tmp,大小为buf + context memset(tmp, 0, sumlen + 1); strncpy(tmp, *buf, buflen);//将buf中的字符串拷贝到tmp strncpy(&tmp[buflen], content, contentlen);//将content中的字符串追加到tmp后面 free(*buf);//释放buf之前的内存 *buf = tmp;//将buf指向tmp的内存区域 } else //第一次调用addurl函数 { int contentlen = strlen(content);//得到content中字符串的长度 *buf = malloc(contentlen + 1);//根据content中字符串的长度动态分配内存空间buf memset(*buf, 0, contentlen + 1); strncpy(*buf, content, contentlen);//将content中字符串拷贝到buf } } //以name为参数,执行“select url, name, description from baidu where name like” SQL语句 int query_result(const char *name, char **buf) { EXEC SQL BEGIN DECLARE SECTION; int iOccurs; short iInd; char sData1[1024];//result buffer; char sData2[1024];//result buffer; char sData3[1024];//result buffer; char sOutput[64]; char sInput[64]; const char *sDySQL; EXEC SQL END DECLARE SECTION; int res = -1; char sSQL[1024]; memset(sSQL, 0, sizeof(sSQL)); sprintf(sSQL, "select url, name, description from baidu where name like '%%%s%%'", name); printf("%s\n", sSQL); SQLCODE = 0; sDySQL = sSQL; sprintf(sOutput, "output%p", pContext);//生成一个在系统中不会重复的字符串 sprintf(sInput, "input%p", pContext);//生成一个在系统中不会重复的字符串 EXEC SQL ALLOCATE DESCRIPTOR :sOutput;//为输出空间分配资源 EXEC SQL ALLOCATE DESCRIPTOR :sInput;//为输入空间分配资源 EXEC SQL PREPARE S FROM :sDySQL;//准备执行指定的SELECT语句 if (SQLCODE != 0) { sql_error();//如果错误,打印错误原因 EXEC SQL DEALLOCATE DESCRIPTOR :sInput;//释放已经分配的输入空间资源 EXEC SQL DEALLOCATE DESCRIPTOR :sOutput;//释放已经分配的输出空间资源 return res; } EXEC SQL DECLARE C CURSOR FOR S;//定义一个游标C EXEC SQL OPEN C USING DESCRIPTOR :sInput;//打开游标C /*选择输出区域*/ EXEC SQL DESCRIBE OUTPUT S USING DESCRIPTOR :sOutput; EXEC SQL WHENEVER NOT FOUND DO BREAK;//如果查询不到记录,下面的while循环break while(1) { /*行数据,输出描述区*/ EXEC SQL FETCH C INTO DESCRIPTOR :sOutput; memset(sData1, 0, sizeof(sData1)); memset(sData2, 0, sizeof(sData2)); memset(sData3, 0, sizeof(sData3)); iInd = 0; iOccurs = 1; EXEC SQL GET DESCRIPTOR :sOutput VALUE :iOccurs :sData1 = DATA, :iInd = INDICATOR;//得到第一个字段值 if (iInd == -1) { strcpy(sData1, "NULL");//如果得到值为NULL } iInd = 0; iOccurs = 2; EXEC SQL GET DESCRIPTOR :sOutput VALUE :iOccurs :sData2 = DATA, :iInd = INDICATOR;//得到第二个字段值 if (iInd == -1) { strcpy(sData2, "NULL");//如果得到值为NULL } iInd = 0; iOccurs = 3; EXEC SQL GET DESCRIPTOR :sOutput VALUE :iOccurs :sData3 = DATA, :iInd = INDICATOR;//得到第三个字段值 if (iInd == -1) { strcpy(sData3, "NULL");//如果得到值为NULL } addurl(sData1, sData2, sData3, buf);//调用addurl,将查询到的行记录转化为HTML形式的字符串 res++; } EXEC SQL CLOSE C;//关闭游标C EXEC SQL DEALLOCATE DESCRIPTOR :sOutput;//释放已经分配的输出空间资源 EXEC SQL DEALLOCATE DESCRIPTOR :sInput;//释放已经分配的输入空间资源 return res; }
CREATE SEQUENCE seq1 increment by 1 start with 1 maxvalue 99999999999; CREATE TABLE baidu (ID int NOT NULL, url varchar2(100), name varchar(100), description varchar2(200)); CREATE UNIQUE INDEX baidu_id ON baidu (ID); CREATE INDEX baidu_name ON baidu (name);
insert into baidu (ID, url, name, description) values (seq1.nextval, 'www.sina.com', 'sina新浪', '新浪的首页'); insert into baidu (ID, url, name, description) values (seq1.nextval, 'www.itcast.cn', 'itcast传智播客', '北京传智播客教育科技有限公司——专注于Java、.Net、iOS、C/C++、php、网页平面设计工程师的培养'); insert into baidu (ID, url, name, description) values (seq1.nextval, '192.168.1.254', 'baidu百度', '百度的首页'); commit;
<head> <meta http-equiv="content-type" content="text/html;charset=utf8"> </head> <html> <title>百度一下,你就知道</title> <body> <img src="bdlogo.gif"> <form action="s" method="get"> <input type="text" name="wd" value="%s" style="font-size:20px;width:400"> <input type="submit" value="百度一下" style="font-size:20px"> </form> %s</body> </html>
【C/C++学院】(28)项目实战HttpServer--源码
原文:http://blog.csdn.net/waldmer/article/details/44300799