您的位置:首页 > 编程语言 > C语言/C++

【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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐