改了一个简单的http服务器遇到一个问题
浏览器请求并成功返回html文件,但是HTML页面中需要加载一些js css文件等,抓包显示服务器能接收到相应的请求并返回了相应的js css文件,但是浏览器报错如图
.C文件
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
#include "httpsever.h"
#define SERVER_PORT 8800
#define ON_DEBUG
const char month_tab[48] =
"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ";
const char day_tab[] = "Sun,Mon,Tue,Wed,Thu,Fri,Sat,";
time_t current_time;
static int debug = 1;
void* do_http_request(void *client_sock); //http处理线程函数
int get_line(int sock, char *buf, int size);
int Parse_Request(struct Request *request);
void Process_Request(struct Request *request);
void GET_Process(struct Request *request);
void POST_Process(struct Request *request);
int Get_FILE(struct Request *request);
int do_http_Response(struct Request *request);
int Headers(struct Request *request);
void Send_Body(struct Request *request);
void rfc822_time_buf(char *buf, time_t s);
void not_found(int client_sock);//404
void unimplemented(int client_sock);//500
void bad_request(int client_sock); //400
void inner_error(int client_sock);
int main(void){
int sock;
struct sockaddr_in server_addr;
//创建socket
sock = socket(AF_INET, SOCK_STREAM, 0);
int opt =1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
//2.清空标签,写上地址和端口号
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;//选择协议族IPV4
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//监听本地所有IP地址
server_addr.sin_port = htons(SERVER_PORT);//绑定端口号80
//绑定socket
bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
//监听socket
listen(sock, 128);
time(¤t_time);
int done =1;
while(done){
struct sockaddr_in client;
int client_sock, len, i;
char client_ip[64];
char buf[256];
pthread_t id;
int* pclient_sock = NULL;
socklen_t client_addr_len;
client_addr_len = sizeof(client);
#ifdef ON_DEBUG
printf("\n等待客户端的连接\n");
#endif
client_sock = accept(sock, (struct sockaddr *)&client, &client_addr_len);
//打印客服端IP地址和端口号
printf("\nclient ip: %s\t port : %d\n",
inet_ntop(AF_INET, &client.sin_addr.s_addr,client_ip,sizeof(client_ip)),
ntohs(client.sin_port));
/*处理http 请求,读取客户端发送的数据*/
// do_http_request(client_sock);
// do{
// len = get_line(client_sock, buf, sizeof(buf));
// if(debug) printf("heard: %s\n", buf);
// }while(len>0);
//启动线程处理http 请求
pclient_sock = (int *)malloc(sizeof(int));
*pclient_sock = client_sock;
pthread_create(&id, NULL, do_http_request, (void *)pclient_sock);
// close(client_sock);
}
close(sock);
return 0;
}
/***************************************************
*请求处理线程 :do_http_request(void* pclient_sock);
*pclient_sock : 客户端socket
****************************************************/
void* do_http_request(void* pclient_sock){
int len = 0;
char buf[256];
struct timeval timeout;
struct Request request,*ptrrequest;
// memset(&request,0,sizeof(request));
timeout.tv_sec = READ_TIMEOUT ;
timeout.tv_usec = 0 ;
/*初始化请求结构体默认参数*/
ptrrequest = &request;
request.client_sock = *(int *)pclient_sock;
request.readTumeout = &timeout;
request.status = 0 ; /* see #defines.h */
request.keepalive = 0; /* keepalive status 1 keepalive , 0 closelive */
request.fp = NULL ; /*descriptor of requested file*/
request.data =NULL ;
request.send_buf = NULL;
/*设置等待超时*/
if (setsockopt(request.client_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == -1) {
printf("setsockopt failed:");
}
do{
request.Request_Length = 0 ; /*Content-Length*/
request.send_buf_len = 0 ;
memset(request.path,0,256); /* pathname of requested file */
int ret = Parse_Request(ptrrequest); /*解析客户端http请求*/
if(ret == 0)
{
Process_Request(ptrrequest); /*处理客户端http请求*/
}
if(request.data) {free(request.data); request.data = NULL;}
if(request.send_buf) {free(request.send_buf); request.send_buf = NULL;}
}while(request.keepalive == 1);
close(request.client_sock);
if(pclient_sock) free(pclient_sock);//释放动态分配的内存
return NULL;
}
/***************************************************
*解析客户端请求 :do_http_request(int client_sock);
*struct Request *request : 客户端请求结构体
****************************************************/
int Parse_Request(struct Request *request)
{
int len = 0;
char buf[256],tempbuf[256];
len = get_line(request->client_sock, buf, sizeof(buf));
#ifdef ON_DEBUG
printf("请求第一行: %s\n", buf);
#endif
if(len > 0){//读到了请求行
/*获取请求方式GET or POST*/
int i=0, j=0;
while(!isspace(buf[j]) && (i<sizeof(tempbuf)-1)){
tempbuf[i] = buf[j];
i++;
j++;
}
tempbuf[i] = '\0';
// #ifdef ON_DEBUG
// printf("request method: %s\n", tempbuf);
// #endif
if(strcmp("GET",tempbuf)==0)
{
request->method = GET;
}else if(strcmp("POST",tempbuf)==0)
{
request->method = POST;
// #ifdef ON_DEBUG
// printf("method: %s\n", tempbuf);
// #endif
}
while(isspace(buf[j]))
{
j++;
};//跳过白空格
i = 0;
/*读取path*/
while(!isspace(buf[j]) && (i<sizeof(request->path)-1)){
request->path[i] = buf[j];
i++;
j++;
}
request->path[i] = '\0';
#ifdef ON_DEBUG
printf("url: %s\n", request->path);
#endif
/*处理path中的?并将读取URL中的数据放到request->data堆空间*/
char *pos = strchr(request->path, '?');
if(pos){
*pos = '\0';
pos++;
request->data = (char *)malloc(sizeof(pos)+1);
memset(request->data,0,sizeof(pos)+1);
strcpy(request->data,pos);
memset(pos,0,sizeof(pos));
#ifdef ON_DEBUG
printf("url data: %s\n", request->data);
#endif
}
/*判断请求文件类型*/
if(strncmp("/js",request->path,3) ==0 )
{
request->Content_Type = JS ;
}else if(strncmp("/css",request->path,4) ==0 )
{
request->Content_Type = CSS ;
}else if(strncmp("/img",request->path,4) ==0 )
{
request->Content_Type = PNG ;
}else if(strncmp("/JPG",request->path,4) ==0 )
{
request->Content_Type = JPG ;
}else if(strncmp("/SET",request->path,4) ==0 )
{
request->Content_Type = SET ; //设置请求
}else if(strncmp("/QUERY",request->path,6) ==0 )
{
request->Content_Type = QUERY ; //查询请求
}else{
request->Content_Type = HTML ;
}
/*请求头部除第一行剩余数据处理,获取request->data*/
do{
memset(buf,0,sizeof(buf));
len = get_line(request->client_sock, buf, sizeof(buf));
#ifdef ON_DEBUG
printf("%s\n", buf);
#endif
if(strncmp("Content-Length",buf,14) == 0) //读取Content-Length参数初始化数据堆空间
{
request->Request_Length = atoi(&buf[16]);
#ifdef ON_DEBUG
printf("request->Length: %d\n", request->Request_Length);
#endif
if(request->Request_Length>0)
request->data = (char *)malloc(request->Request_Length+1);
memset(request->data,0,request->Request_Length+1);
}
else if(strncmp("Connection",buf,10) == 0) //读取Connection参数
{
if(strncmp("keep-alive",&buf[12],10) == 0)
{
request->keepalive = 1;
}else{
request->keepalive = 0;
}
}
}while(len>0);
/*读取请求数据实体*/
if(request->Request_Length>0)
{
len = read(request->client_sock, request->data, request->Request_Length);
#ifdef ON_DEBUG
printf("data: %s\n", request->data);
#endif
}
}else{
request->keepalive = 0;
return -1;
}
return 0;
}
/***************************************************
*请求处理 :Process_Request(struct Request *request);
*struct Request *request : 客户端请求结构体
****************************************************/
void Process_Request(struct Request *request)
{
switch(request->method)
{
case GET :
//GET....
GET_Process(request);
break;
case POST :
//POST....
POST_Process(request);
break;
}
}
//返回值: -1 表示读取出错, 等于0表示读到一个空行, 大于0 表示成功读取一行
int get_line(int sock, char *buf, int size){
int count = 0 ;
char ch = '\0';
int len = 0;
while( (count<size - 1) && ch!='\n'){
len = read(sock, &ch, 1);
if(len == 1){
if(ch == '\r'){
continue;
}else if(ch == '\n'){
//buf[count] = '\0';
break;
}
//这里处理一般的字符
buf[count] = ch;
count++;
}else if( len == -1 ){//读取出错
perror("read failed");
count = -1;
break;
}else {// read 返回0,客户端关闭sock 连接.
fprintf(stderr, "client close.\n");
count = -1;
break;
}
}
if(count >= 0) buf[count] = '\0';
return count;
}
void GET_Process(struct Request *request)
{
char temppath[256] = {0};
strcat(temppath,"./www");
if(strcmp("/",request->path) == 0) //GET请求空路劲时默认请求login.html
{
strcat(request->path,"login.html");
}
if(request->Content_Type!=SET && request->Content_Type!=QUERY)
{//请求文件
strcat(temppath,request->path);
memcpy(request->path,temppath,strlen(temppath));
int ret = Get_FILE(request);
if(ret == -1)
return ;
}
do_http_Response(request);
}
int do_http_Response(struct Request *request)
{
if(request->Content_Type == SET || request->Content_Type == QUERY)
{
//进行设置或者查询任务并且返回,回复信息长度和回复信息
}
int ret = Headers(request);
if(!ret)
{
Send_Body(request);
}
if(request->fp!=NULL)
{
fclose(request->fp);
request->fp = NULL;
}
}
/****************************
*返回关于响应文件信息的http 头部
*输入:
* client_sock - 客服端socket 句柄
* resource - 文件的句柄
*返回值: 成功返回0 ,失败返回-1
******************************/
int Headers(struct Request *request){
struct stat st;
int fileid = 0;
char tmp[64];
char buf[1024]="HTTP/1.0 200 OK\r\nDate: "
" "
"\r\nServer: web Server\r\n";
rfc822_time_buf(buf + 23, 0);
// strcpy(buf, "HTTP/1.0 200 OK\r\n");
// strcat(buf, "Server: web Server\r\n");
switch(request->Content_Type)
{
case JPG :
strcat(buf, "Content-Type: image/jpeg\r\n");
break;
case CSS :
strcat(buf, "Content-Type: text/css\r\n");
break;
case JS :
strcat(buf, "Content-Type: text/javascript\r\n");
break;
case PNG :
strcat(buf, "Content-Type: image/png\r\n");
break;
default :
strcat(buf, "Content-Type: text/html\r\n");
break;
}
if(request->keepalive == 1)
{
strcat(buf, "Connection: Keep-Alive\r\n");
}else{
strcat(buf, "Connection: Close\r\n");
}
snprintf(tmp, 64, "Keep-Alive: timeout=%ld\r\n", request->readTumeout->tv_sec);
strcat(buf, tmp);
memset(tmp,0,64);
if(request->Content_Type == SET || request->Content_Type == QUERY)
{
snprintf(tmp, 64, "Content-Length: %d\r\n\r\n", request->send_buf_len);
}else{
fileid = fileno(request->fp);
if(fstat(fileid, &st)== -1){
inner_error(request->client_sock);
return -1;
}
snprintf(tmp, 64, "Content-Length: %ld\r\n\r\n", st.st_size);
}
strcat(buf, tmp);
#ifdef ON_DEBUG
printf("Send Header:\n%s", buf);
#endif
if(send(request->client_sock, buf, strlen(buf), 0)<0){
fprintf(stderr, "send failed. data: %s, reason: %s\n", buf, strerror(errno));
return -1;
}
return 0;
}
/****************************
*说明:实现文件的内容按行读取并送给客户端
****************************/
void Send_Body(struct Request *request){
char buf[1024];
int count = 1;
if(request->Content_Type == SET || request->Content_Type == QUERY)
{
int len = write(request->client_sock, request->send_buf, request->send_buf_len);
while(len<0 && count<3){//发送body 的过程中出现问题,重传
len = write(request->client_sock, request->send_buf, request->send_buf_len);
count ++;
}
}
else{
fgets(buf, sizeof(buf), request->fp);
while(!feof(request->fp)){
int len = write(request->client_sock, buf, strlen(buf));
count = 1;
while(len<0 && count<3){//发送body 的过程中出现问题,重试
fprintf(stderr, "send body error. reason: %s\n", strerror(errno));
len = write(request->client_sock, buf, strlen(buf));
count ++;
}
if(count == 3 && len<0 )
{
break;
}
#ifdef ON_DEBUG
fprintf(stdout, "%s", buf);
#endif
fgets(buf, sizeof(buf), request->fp);
}
}
}
void POST_Process(struct Request *request)
{
//若果请求路径为/(默认是HTML类型)
}
int Get_FILE(struct Request *request)
{
struct stat st;
if(stat(request->path, &st)==-1){//文件不存在或是出错
not_found(request->client_sock);
return -1;
}else {//文件存在
// if(S_ISDIR(st.st_mode)){ //判断request->path是否是,目录是为真
// }
request->fp = fopen(request->path, "r");
if(request->fp == NULL){
not_found(request->client_sock);
return -1;
}
}
}
/* rfc822 (1123) time is exactly 29 characters long
* "Sun, 06 Nov 1994 08:49:37 GMT"
*/
void rfc822_time_buf(char *buf, time_t s)
{
struct tm *t;
char *p;
unsigned int a;
if (!s) {
t = gmtime(¤t_time);
} else
t = gmtime(&s);
p = buf + 28;
/* p points to the last char in the buf */
p -= 3;
/* p points to where the ' ' will go */
memcpy(p--, " GMT", 4);
a = t->tm_sec;
*p-- = '0' + a % 10;
*p-- = '0' + a / 10;
*p-- = ':';
a = t->tm_min;
*p-- = '0' + a % 10;
*p-- = '0' + a / 10;
*p-- = ':';
a = t->tm_hour;
*p-- = '0' + a % 10;
*p-- = '0' + a / 10;
*p-- = ' ';
a = 1900 + t->tm_year;
while (a) {
*p-- = '0' + a % 10;
a /= 10;
}
/* p points to an unused spot to where the space will go */
p -= 3;
/* p points to where the first char of the month will go */
memcpy(p--, month_tab + 4 * (t->tm_mon), 4);
*p-- = ' ';
a = t->tm_mday;
*p-- = '0' + a % 10;
*p-- = '0' + a / 10;
*p-- = ' ';
p -= 3;
memcpy(p, day_tab + t->tm_wday * 4, 4);
}
#if 1
void not_found(int client_sock){
const char * reply = "HTTP/1.0 404 NOT FOUND\r\n\
Content-Type: text/html\r\n\
\r\n\
<HTML lang=\"zh-CN\">\r\n\
<meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\">\r\n\
<HEAD>\r\n\
<TITLE>NOT FOUND</TITLE>\r\n\
</HEAD>\r\n\
<BODY>\r\n\
文件不存在!\r\n\
The server could not fulfill your request because the resource specified is unavailable or nonexistent.\r\n\
</BODY>\r\n\
</HTML>"
;
int len = write(client_sock, reply, strlen(reply));
if(debug) fprintf(stdout, reply);
if(len <=0){
fprintf(stderr, "send reply failed. reason: %s\n", strerror(errno));
}
}
void unimplemented(int client_sock){
const char * reply = "HTTP/1.0 501 Method Not Implemented\r\n\
Content-Type: text/html\r\n\
\r\n\
<HTML>\r\n\
<HEAD>\r\n\
<TITLE>Method Not Implemented</TITLE>\r\n\
</HEAD>\r\n\
<BODY>\r\n\
HTTP request method not supported.\r\n\
</BODY>\r\n\
</HTML>"
;
int len = write(client_sock, reply, strlen(reply));
if(debug) fprintf(stdout, reply);
if(len <=0){
fprintf(stderr, "send reply failed. reason: %s\n", strerror(errno));
}
}
void bad_request(int client_sock){
const char * reply = "HTTP/1.0 400 BAD REQUEST\r\n\
Content-Type: text/html\r\n\
\r\n\
<HTML>\r\n\
<HEAD>\r\n\
<TITLE>BAD REQUEST</TITLE>\r\n\
</HEAD>\r\n\
<BODY>\r\n\
Your browser sent a bad request!\r\n\
</BODY>\r\n\
</HTML>"
;
int len = write(client_sock, reply, strlen(reply));
if(len<=0){
fprintf(stderr, "send reply failed. reason: %s\n", strerror(errno));
}
}
void inner_error(int client_sock){
const char * reply = "HTTP/1.0 500 Internal Sever Error\r\n\
Content-Type: text/html\r\n\
\r\n\
<HTML lang=\"zh-CN\">\r\n\
<meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\">\r\n\
<HEAD>\r\n\
<TITLE>Inner Error</TITLE>\r\n\
</HEAD>\r\n\
<BODY>\r\n\
服务器内部出错.\r\n\
</BODY>\r\n\
</HTML>"
;
int len = write(client_sock, reply, strlen(reply));
if(debug) fprintf(stdout, reply);
if(len <=0){
fprintf(stderr, "send reply failed. reason: %s\n", strerror(errno));
}
}
#endif
#ifndef HTTPSEVER
#define HTTPSEVER
/*请求类型*/
#define GET 1
#define POST 2
/*请求文件类型*/
#define JPG 1
#define CSS 2
#define JS 3
#define HTML 4
#define PNG 5
#define SET 6 //设置请求/SET
#define QUERY 7 //查询请求/QUERY
#define READ_TIMEOUT 3 /*read超时时间*/
#include <stdio.h>
#include <sys/time.h>
struct Request { /* pending requests */
int client_sock; /* client's socket fd */
int method; /* M_GET, M_POST, etc. */
int status; /* see #defines.h */
int keepalive; /* keepalive status 1 keepalive , 0 closelive */
int Request_Length; /*Content-Length*/
int send_buf_len;
int Content_Type; /*Type of requested file*/
char path[256]; /* pathname of requested file */
FILE * fp; /*descriptor of requested file*/
char *data;
char *send_buf;
struct timeval *readTumeout;
};
#endif