【C语言】【unix c】web服务器项目代码
2017-10-16 23:27
148 查看
思路: 先建立好服务器和客户端之间的链接(socket->bind->listen->循环accept->close) 然后操作accept后的事情(业务处理) 业务处理: 浏览器发送信息->服务器接收到后将接受到的信息存在一个地方->取出信息中第一行中的 方法 目录文件 协议版本->将目录与规定目录进行拼接->在拼接的后的目录下察看文件是否存在,是否可读决定返回什么信息->若文件存在->判断文件的类型,打开文件,将需要的信息返回客户端->关闭链接进行下次处理 p_net.h //头文件 #ifndef __P_NET_H__ #define __P_NET_H__ #include <sys/types.h> #include <sys/socket.h> #include <ctype.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdlib.h> #include <sys/wait.h> #include <unistd.h> //这个类型中存放着地址家族中的信息,在这里将类型起了一个别名,有于强制转换 typedef struct sockaddr SA; //这是实际的存储地址信息的地方,这是IPV4的格式 typedef struct sockaddr_in SA4; //这个结构体里面存放了浏览器请求信息中的一些信息 typedef struct{ char method[50]; //处理方法 GET char uri[128];//目录,文件位置 /9.png char version[50];//协议版本号 HTTP/1.1 }req_t; //这个结构体里面存放响应浏览器的一些信息 typedef struct response{ int code; //返回文件是否存在等信息200 404 char mime[32];// text/heml 类型 }res_t; int p_listen(int,int); void do_works(int); #endif //__P_NET_H__ p_net.c //这里进行的是服务器的准备动作,使服务器进入监听状态 #include <stdio.h> #include <p_net.h> //这里是默认的访问位置 char work_dir[128] = "/home/tarena/day/day38/www/html\0"; int p_listen(int port, int backlog) { int s_fd; SA4 addr; char ip[128]; pid_t pid; //创建socket s_fd = socket(AF_INET,SOCK_STREAM,0); if(s_fd == -1) { perror("socket"); return -1; } //初始化ipv4地址 addr.sin_family = AF_INET; //初始化需要将端口号将主机字节序转换为网络字节序 addr.sin_port = htons(8000); addr.sin_addr.s_addr = htonl(INADDR_ANY); //将s_fd和addr地址空间绑定 int b = bind(s_fd, (SA*)&addr, sizeof(addr)); if(b == -1) { perror("bind"); return -1; } //将s_fd设置为被动监听 listen(s_fd, backlog);//5是最多可以存放5个链接 return s_fd; } servers.c //这里进行的是取出队列中的链接以建立链接创建子进程 #include <stdio.h> #include <p_net.h> int main(void) { int s_fd; int c_fd; SA4 addr; //存放地址家族信息的地方 char ip[128]; //存ip信息的地方 pid_t pid; //进入监听状态 s_fd = p_listen(8000,5); while(1) { //从未决链接队列里取出一个链接 c_fd = accept(s_fd, NULL, NULL); //不需要显示是谁访问的所以后面设置为NULL if(c_fd == -1) { perror("accept"); return -1; } //创建子进程 pid = fork(); if(pid == -1) { perror("fork"); return -1; } if(pid == 0) { close(s_fd);//连接成功后关闭套接字,防止资源浪费 //业务处理 do_works(c_fd); //关闭本次链接,结束本次通讯 close(c_fd);//?????????? exit(0); } else { close(c_fd); waitpid(-1, NULL,WNOHANG); //等待子进程的结束后,回收资源 } } close(s_fd); return 0; } works.c //这里进行业务的处理,处理收到的信息和返回处 4000 理后的信息 #include <stdio.h> #include <p_net.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> //扩展作用域 extern char work_dir[128]; // 6 判断文件的类型 static char *get_mime(const char *file, char *mime) { char *p = strrchr(file, '.'); //取从最右边的.后面的内容 if(strcmp(p, ".html") == 0){ strcpy(mime, "text/html"); } if(strcmp(p,".jpg") == 0) { strcpy(mime,"image/jpg"); } if(strcmp(p,".png") == 0) { strcpy(mime,"image/png"); } return; } // 5 判断文件是否存在和有效性,存在200无效400 static int file_exist(const char *file) { printf("file_exist %s\n", file); if(access(file,F_OK) == -1) { //测试是否存在,存在返回0,不存在返回-1 printf("F\n"); return 404; } if(access(file,R_OK) == -1) { //测试文件是否可读,不可读返回 -1 printf("R\n"); return 404; } return 200; } // 4 拼接目录 static char *get_path(const req_t *req, char *path) { strcpy(path, work_dir); strcat(path, "/"); strcat(path, req->uri); printf("uri:%s\n",req->uri); printf("path:%s\n",path); return path; } // 3 (拼接目录)准备好要返回的头文件信息 static int orga_mess(const req_t *req, res_t *res) { char file[512]; bzero(file,512); //将空间清空防止否垃圾数据 bzero(res->mime,32); //拼接目录 get_path(req,file); printf("file:%s\n", file); printf("mess:%d\n",res->code); //判断文件是否存在或有效,并赋值给返回信息的头信息的结构体里 res->code = file_exist(file);//获取404或200 printf("mess2:%d\n",res->code); //判断文件的类型,赋值给返回信息的头信息的结构体里 get_mime(file, res->mime); printf("path:%s\n",file); printf("mime:%s\n",res->mime); return 0; } // 2 进行解析,分离出协议,方法,目录 int get_request(int fd, req_t *r) { char buf[512]; //buf是用来存放接收到的信息包括各种辅助信息 int val = read(fd, buf, 512); //将收到的信息存放到buf中 printf("get_request buf:\n%s", buf); if(val > 0) { //如果接收到信息执行下面 sscanf(buf,"%s /%s %s\r\n", r->method, r->uri, r->version);//按格式将数组中的信息存到指定位置???sscanf???? } // printf("uri:%s\nmethod:%s\nversion%s\n",r->uri,r->method,r->version); return 0; } // 8 文件没有找到 返回的404信息 static int response_b_404(int fd) { char *f_line = "HTTP/1.1 404 OK\r\nContent-Type:text/html\r\n\r\n"; char *body = "<html><body>file not found!</body></heml>"; write(fd,f_line,strlen(f_line)); //直接返回需要的信息 write(fd,body,strlen(body)); return 0; } // 9 打开文件,返回文件中的信息 int mycat(int fd, char *file){ printf("%s",file); int s_fd = open(file, O_RDONLY); char buf[128]; bzero(buf,128); if(s_fd == -1) { perror("open"); return -1; } int r; while((r = read(s_fd, buf, 128)) > 0 ) { write(fd,buf,r); // printf("%s",buf); } close(s_fd); } // 8 文件存在并且有效 static int response_b_200(int fd,req_t *req, res_t *res) { char f_line[128]; char content[128]; char path[512]; bzero(f_line,128); bzero(content,128); bzero(path,128); //拼接头文件信息,第一行 sprintf(f_line,"%s %d OK\r\n",req->version, res->code); //拼接头文件信息,第二行 sprintf(content,"Content-Type:%s\r\n\r\n", res->mime); printf("%s\n",path); //获得文件的地址 get_path(req,path); //将头信息返回 write(fd,f_line,strlen(f_line)); write(fd,content,strlen(content)); printf("%s\n",path); //读取文件的信息,并文件输出到浏览器 mycat(fd,path); // printf("code:%d\n",res->code); return 0; } // 7 处理信息并返回浏览器 static int reponse_b(int fd,req_t *req, res_t *res) { printf("rescode:%d\n", res->code); if(res->code == 404) { //根据判断出的文件信息决定返回的信息 response_b_404(fd); } else { response_b_200(fd, req, res); } return 0; } // 1 void do_works(int fd) { //fd是链接的文件描述符 req_t req; res_t res; //获取第一行信息,将信息解析并保存,返回 get_request(fd, &req);//处理 //printf("%s %s %s\n", req.method, req.uri, req.version); //根据请求信息组织响应消息 orga_mess(&req, &res); //回应浏览器 reponse_b(fd,&req,&res); return; }
相关文章推荐
- 【C语言】【unix c】web服务器项目笔记
- web项目发布到服务器上,但是修改的css和js文件没有起作用,显示的还是之前没有修改的代码
- web 项目中的文件上传服务器的代码实现
- 试图运行项目时出错:无法在web服务器上启动项目得解决办法
- Android中网络编程以及与服务器上Web项目的基础交互
- VS2013打开项目提示"Asp.net4.5未在web服务器上注册 "
- j2ee的web项目,报错,如果报错的代码位于被封装的class文件中,怎么看报错的class所在的jar包?
- {最代码}如何在eclipse jee中检出项目并转换为Maven project,最后转换为Dynamic web project
- Tengine web服务器--淘宝web服务器项目
- Linux下代码从SVN服务器到web服务器的自动化部署[svn update $WEB --username mrwei --password jiaowomrwei]
- idea开发web项目打包上传到服务器
- 试图运行项目时报错:无法在web服务器上启动调试
- Web服务器错误代码大全
- 将Web项目War包部署到Tomcat服务器基本步骤
- ASP.NET中动态修改web.config中的设置项目(前台代码)
- 无法在web服务器上启动项目另一种解决方法
- Web开发、测试环境搭建(LAMP、SVN服务器、Laravel项目创建)
- 试图运行项目时出错:无法在web服务器上启动调试。调试失败,因为没有启动集成Windows身份验证
- VS2013新建asp.net空网站项目失败,配置IISexpress失败,未能找到web服务器“http://localhost”解决方案
- Eclipse部署Maven web项目到tomcat服务器时,没有将lib下的jar复制过去的解决办法