您的位置:首页 > 理论基础 > 计算机网络

简单HTTP服务器(select模型)

2015-05-19 15:41 267 查看
server.c

<pre name="code" class="cpp">#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <signal.h>

#define SERVER_NAME "IAMCAP-SERVER"
#define PROTOCOL    "HTTP/1.1"
#define REQUESTLEN 4096
#define RESPONSELEN  1024000

#define LISTENNUM 5

#define TIMELEN 55
#define TEMPLEN 100
#define BUFFERLEN 1024

#define HOMEPATH  "/Users/iamcap/http/showhttp/"

static char* add_header(int , char *, char *, off_t , char *, int );
void parsedata(char*,int);

int main(int argc, char **argv){
if(argc <=2){
printf("usage: %s ip_address port_number\n", (argv[0]));
return 1;
}
const char *ip = argv[1];
int port = atoi(argv[2]);

//initialize the struct

struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
inet_pton(AF_INET, ip, &address.sin_addr);
address.sin_port = htons(port);

//reuse the port

int sock = socket(PF_INET, SOCK_STREAM, 0);
assert( sock >= 0);
int opt = 1;
setsockopt(sock, SOL_SOCKET,SO_REUSEADDR, &opt, sizeof(opt));

int ret = bind(sock, (struct sockaddr*)&address, sizeof(address));
assert(ret != -1);

printf("listening ...\n");
ret = listen(sock, LISTENNUM);
assert(ret != -1);
fd_set fp_socketselect;
FD_ZERO(&fp_socketselect);
FD_SET(sock,&fp_socketselect);

int max_fp = sock;

struct sockaddr_in client;
socklen_t client_addrlength = sizeof(client);

int temp;

int  fdarr[65535];

fdarr[0] = sock;
printf("------>>%d\n",fdarr[0]);
int boundcount = 1;
signal(SIGCHLD,SIG_IGN);
while(1){
printf("i am coming to accept\n");

temp = accept(sock,(struct sockaddr*)&client,&client_addrlength);
printf("connect = %d",temp);

max_fp = max_fp > temp ? max_fp : temp;
fdarr[boundcount++]=temp;
FD_SET(temp, &fp_socketselect);

int num = select(max_fp+1,&fp_socketselect,NULL,NULL,NULL);
//return the number which suit to the rules
printf("num = %d\n",num);
printf("boundcount = %d",boundcount);
if(num > 0){
int i = 0;
printf("polling..\n");
while(i++ < boundcount )
{
FD_SET(fdarr[i],&fp_socketselect);
if(FD_ISSET(fdarr[i],&fp_socketselect)){

if(fdarr[i] == sock){
temp = accept(sock,(struct sockaddr*)&client,&client_addrlength);
max_fp = max_fp > temp ? max_fp : temp;
fdarr[boundcount++]=temp;
FD_SET(temp, &fp_socketselect);
printf("\nconnected with ip: %s and port: %d\n", inet_ntoa(client.sin_addr),ntohs(client.sin_port));

}else if(fdarr[i]>3){
char recvdata[REQUESTLEN];
memset(recvdata,'\0',REQUESTLEN);
int ret = recv(fdarr[i],recvdata,REQUESTLEN-1,0);
printf("\n%s\n", recvdata);
pid_t pid = fork();
if(-1 == pid){
printf("fork() is wrong!!!\n");
}else if(0 == pid){
parsedata(recvdata,fdarr[i]);
break;
}else{
close(fdarr[i]);
}
}
}
}

}else if(0==num){
printf("time out \n");
}else{
printf("something wrong\n");
}

}
close(sock);
return 0;
}

// send header to the  browser

static char* add_header(int status, char *title, char *mime_type, off_t length, char *buffer , int buffersize)
{

char temp[TEMPLEN];

memset(buffer, 0, sizeof(buffersize));
sprintf(temp, "%s %d %s\r\n", PROTOCOL, status, title);

strcat(buffer, temp);
sprintf(temp, "Server: %s\r\n", SERVER_NAME);
strcat(buffer, temp);
sprintf(temp, "Connection: Keep-Alive\r\n");
strcat(buffer, temp);
sprintf(temp, "Content-Type: %s\r\n", mime_type);
strcat(buffer, temp);
sprintf(temp, "Content-Length: %d\r\n", (int)length);
strcat(buffer, temp);
sprintf(temp, "Content-Language: zh-CN\r\n");
strcat(buffer, temp);
strcat(buffer, "\r\n");
return buffer;
}

static char* get_mime_type(char *filename)
{
char *postfix;
postfix = strrchr(filename, '.');
if (!strcasecmp(postfix, ".html") || !strcasecmp(postfix, ".htm")){
return "text/html; charset=UTF-8";
}else if (!strcasecmp(postfix, ".jpg") || !strcasecmp(postfix, ".jpeg")){
return "image/jpeg";
}else{
return "text/plain; charset=UTF-8";
}
}

void parsedata(char *recvdata, int connectfd){

if(chdir(HOMEPATH)<0){
// printf("chdir error\n");
exit(0);
}
char method[BUFFERLEN];
char path[BUFFERLEN];
char protocol[BUFFERLEN];
memset(method,'\0',BUFFERLEN);
memset(path,'\0',BUFFERLEN);
memset(protocol,'\0',BUFFERLEN);

sscanf(recvdata, "%[^ ] %[^ ] %[^ ]", method, path, protocol);
//open file or dir
struct stat property;
stat(path,&property);
if(S_ISDIR(property.st_mode)){

if(0 == strcmp(path,"/")){
if(0 == strcasecmp(method,"GET"))
{

FILE *fp;
if(fp = fopen("index.html","r")){
char head[BUFFERLEN];
memset(head,'\0',BUFFERLEN);
stat(path+1,&property);
stat("index.html",&property);

add_header(200, "OK", "text/html", property.st_size, head, BUFFERLEN);
char temp[RESPONSELEN];
memset(temp,'\0',RESPONSELEN);
strcpy(temp,head);
fread(temp+strlen(head),1,property.st_size,fp);
send(connectfd, temp, strlen(head)+property.st_size,0);

close(connectfd);
}
}else if(0 == strcasecmp(method,"POST")){

char *postemp=strtok(recvdata, "\r\n\r\n");
char *pos = postemp;
while (postemp) {
postemp=strtok(NULL, "\r\n\r\n");
if(postemp){
pos = postemp;
}

}

char mes[500]={"<html><script>alert(\""};
strcat(mes,pos);
strcat(mes,"\");</script></html>");

char head[BUFFERLEN];
memset(head,'\0',BUFFERLEN);
add_header(200, "OK", "text/html", strlen(mes), head, BUFFERLEN);
char temp[RESPONSELEN];
memset(temp,'\0',RESPONSELEN);
strcpy(temp,head);
strcat(temp,mes);
send(connectfd, temp, strlen(head)+strlen(mes),0);

close(connectfd);
}
}else{        //other dir
exit(0);
}
}else{                               //if it is a file
if(0 == strcasecmp(method,"GET")){
FILE *fp;
if(fp = fopen(path+1,"rb")){
char head[BUFFERLEN];
memset(head,'\0',BUFFERLEN);
stat(path+1,&property);
add_header(200, "OK", get_mime_type((path + 1)), property.st_size, head, BUFFERLEN);
char temp[RESPONSELEN];
memset(temp,'\0',RESPONSELEN);
strcpy(temp,head);
fread(temp+strlen(head),1,property.st_size,fp);
send(connectfd, temp, strlen(head)+property.st_size,0);
close(connectfd);
}
}else if(0 == strcasecmp(method,"POST")){

}else if(0 == strcasecmp(method,"HEAD")){

}else if(0 == strcasecmp(method,"PUT")){

}else{
exit(0);
}
}
}


index.html

<html>
<script type="text/javascript">
<span style="white-space:pre">	</span>function mdo(){
<span style="white-space:pre">		</span>var flag = confirm("Do you want to download ?");
<span style="white-space:pre">		</span>if(flag == true){
<span style="white-space:pre">			</span>var x = document.getElementById('mydo').href = "1.zip";
<span style="white-space:pre">			</span>alert("you confirmed");
<span style="white-space:pre">		</span>}else{
<span style="white-space:pre">			</span>alert("you canceled");
<span style="white-space:pre">		</span>}

<span style="white-space:pre">	</span>}

</script>
<span style="white-space:pre">	</span><body>
<span style="white-space:pre">		</span><H1>this is a page</H1>
<span style="white-space:pre">		</span><img src="mypic.jpg" />
<span style="white-space:pre">		</span><form  method="post">
<span style="white-space:pre">		</span><input id="firstid" type="text" name="first" />
<span style="white-space:pre">		</span><input id="secondid" type="text" name="second"/>
<span style="white-space:pre">		</span><input id="sumid" type="text" name="sum" readonly="true">
<span style="white-space:pre">		</span><input type="submit" value="compute" onclick="location.reload(true)">
<span style="white-space:pre">		</span></form>
<span style="white-space:pre">		</span><a id="mydo" href="" onclick="mdo()" >click to download zip</a>
<span style="white-space:pre">	</span></body>
</html>


加入了一个POST请求,并将请求数据用alert显示出来。带了文件下载功能,附带了CGI的处理,就将输入的数传给服务器,服务器执行一段shell脚本,然后将数据打包回馈给浏览器,在代码中,我使用了中间文件存储处理生成的结果,后来我发现可以利用更好的方法利用 popen函数来处理,自己改动吧!

CGI执行的代码:

#!/bin/sh
echo "<HTML><HEAD>"
echo "<TITLE>bigger or not</TITLE>"
echo "</HEAD><BODY>"
if [ $1 -gt 0 ]
then echo "<script>alert(\"$1 > 0\");</script>"
else
echo "<script>alert(\"$1 <= 0\");</script>"
fi
echo "</BODY></HTML>"
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: