Linux下实现web服务器
说明:暂时只是实现了静态网页的响应
1 #include <stdio.h> 2 #include <sys/types.h> /* See NOTES */ 3 #include <sys/socket.h> 4 #include <string.h> 5 #include <arpa/inet.h> 6 #include <unistd.h> 7 #include <signal.h> 8 #include <sys/wait.h> 9 #include <sys/stat.h> 10 #include <fcntl.h> 11 #include <stdlib.h> 12 13 #define PORT 8000 14 char* msg_err="HTTP/1.1 404 NO FOUND\r\nContent-Type:text/html\r\n\r\n"; 15 char* msg_text="HTTP/1.1 200 OK\r\nContent-Type:text/html\r\n\r\n"; 16 char* msg_jpg="HTTP/1.1 200 OK\r\nContent-Type:image/jpg\r\n\r\n"; 17 char* msg_png="HTTP/1.1 200 OK\r\nContent-Type:image/png\r\n\r\n"; 18 char* work_dir="/home/soft01/Hector/Unixc/webProject/hah/www"; 19 char* work_dir_err="/home/soft01/Hector/Unixc/webProject/hah/err_404.html"; 20 21 //定义http协议 结构体 22 typedef struct http{ 23 char method[12]; 24 char filename[128]; 25 char protol[16]; 26 }utr_t; 27 28 //自定义信号处理函数 29 //回收子进程 30 void sig_do(){ 31 wait(NULL); 32 return; 33 } 34 35 //响应 36 void write_client(char* str,int fd,char* msg){ 37 char status[100000]; 38 int fd_open=open(str,O_RDONLY); 39 if(fd_open==-1){ 40 perror("open"); 41 int fd_open=open(work_dir_err,O_RDONLY); 42 int nlen=read(fd_open,status,100000); 43 write(fd,msg_err,strlen(msg_err)); 44 write(fd,status,nlen); 45 return; 46 } 47 int nlen=read(fd_open,status,100000); 48 write(fd,msg,strlen(msg)); 49 write(fd,status,nlen); 50 return; 51 } 52 53 //判断图片文本 54 void judge_text_or_png(char* str,int fd){ 55 char* msg="<html>\n<body>\n<h1>404\n</body>\n</html>\n"; 56 if(str==NULL){return;} 57 char* tmp=NULL; 58 if((tmp=strstr(str,".jpg"))!=NULL){ 59 write_client(str,fd,msg_jpg); 60 } 61 else if((tmp=strstr(str,".png"))!=NULL){ 62 write_client(str,fd,msg_png); 63 } 64 else if((tmp=strstr(str,".html"))!=NULL){//文本 65 write_client(str,fd,msg_text); 66 } 67 else{ 68 write(fd,msg_err,strlen(msg_err)); 69 write(fd,msg,strlen(msg)); 70 } 71 return; 72 } 73 74 //子进程响应客户端 75 void request_do(int fd){ 76 utr_t http; 77 char path[128]; 78 char buf[1024]; 79 int len=read(fd,buf,1024); 80 sscanf(buf,"%s %s %s\r\n",http.method,http.filename,http.protol); 81 if(strcmp(http.filename,"/")==0){ 82 strcpy(http.filename,"/index.html"); 83 } 84 85 strcpy(path,work_dir); 86 strcat(path,http.filename); 87 strcpy(http.filename,path); 88 printf("method:%s filename:%s protol:%s\n", http.method,http.filename,http.protol); 89 90 //判断图片文本 91 judge_text_or_png(http.filename,fd); 92 93 return; 94 } 95 96 int main(){ 97 struct sockaddr_in serv; 98 struct sockaddr_in clie; 99 socklen_t clie_len; 100 signal(SIGCHLD,sig_do); 101 //创建socket通讯端口 102 int sfd=socket(AF_INET,SOCK_STREAM,0); 103 if(sfd==-1){ 104 perror("socket"); 105 return -1; 106 } 107 108 //初始化服务器serv 109 serv.sin_family=AF_INET; 110 serv.sin_port=htons(PORT); 111 serv.sin_addr.s_addr=htonl(INADDR_ANY); 112 //将sfd绑定到服务器 113 int b=bind(sfd,(struct sockaddr*)&serv,sizeof(serv)); 114 if(b==-1){ 115 perror("bind"); 116 return -1; 117 } 118 listen(sfd,10); 119 while(1){ 120 clie_len=sizeof(clie); 121 //建立和客户端的连接 122 int cfd=accept(sfd,(struct sockaddr*)&clie,&clie_len); 123 if(cfd==-1){ 124 perror("accept"); 125 return -1; 126 } 127 pid_t pid=fork(); 128 if(pid==-1){ 129 perror("pid"); 130 return -1; 131 } 132 if(pid==0){//子进程 133 close(sfd); 134 //响应客户端请求 135 request_do(cfd); 136 close(cfd); 137 exit(0); 138 } 139 else{//父进程 140 close(cfd); 141 } 142 143 } 144 return 0; 145 }