【http-server工作流程demo

http-server

http协议格式

在这里插入图片描述

http-server 代码

#include <arpa/inet.h>
#include <ctype.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <sys/epoll.h>

#define PORT 9001
#define QUEUE_MAX_COUNT 5
#define BUFF_SIZE 1024

#define SERVER_STRING "Server: hoohackhttpd/0.1.0\r\n"

#define OK 1
#define FAILED -1

#define CR '\r'
#define LF '\n'
#define CRLF "\r\n"
#define BLANK ' '
#define COLON ':'

#define DEBUG 0

#define HTML_PATH "/home/king/share/hik/Makehttpd-master/"

#define dprint(expr) printf(#expr " = %g\n", expr)

#define EPOLL_MAX_NUM 1000

#define RESPONSE_STR "<!DOCTYPE html><html><head><title>Welcome to http server!</title><style>body{width: 35em; \
margin: 0 auto;font-family: Tahoma, Verdana, Arial, sans-serif;}</style></head><body><h1>Welcome to http server!</h1></body></html>"

typedef struct _request_packet {
	char *method;
	char *url;
	char *version;
} req_pack;

void success_header(int sockfd)
{
	char buf[BUFF_SIZE];
	strcpy(buf, "HTTP/1.1 200 OK\r\n");
	send(sockfd, buf, strlen(buf), 0);
	strcpy(buf, SERVER_STRING);
	send(sockfd, buf, strlen(buf), 0);
	sprintf(buf, "Content-Type: text/html\r\n");
	send(sockfd, buf, strlen(buf), 0);
	strcpy(buf, "\r\n");
	send(sockfd, buf, strlen(buf), 0);
}

void process_get(int sockfd, req_pack *rp)
{
	success_header(sockfd);
	send(sockfd, RESPONSE_STR, strlen(RESPONSE_STR), 0);
}

int parse_start_line(int sockfd, char *recv_buf, req_pack *rp)
{
	char *p = recv_buf;
	char *ch = p;
	int i = 0;
	int k = 0;

	if (*ch < 'A' || *ch > 'Z') {
		return -1;
	}

	printf("recv buf : %s \n", recv_buf);
	while (*ch != CR) {
		if (*ch != BLANK) {
			k++;
		} else {
			char* tmp= (char *)malloc(k * sizeof(char));
			memset(tmp, 0, sizeof(char));
			int offset = 0;
			if(i >= 1)
			{
				offset += strlen(rp->method);
			}
			if(i >= 2)
			{
				offset += strlen(rp->url);
			}
			strncpy(tmp, recv_buf + offset, k);
			if(i == 0)
			{
				rp->method = tmp;
			}else if(i == 1)
			{
				rp->url = tmp;
			}else{
				rp->version = tmp;
			}
			k = 0;
			i++;
		}
		ch++;
	}

	return (i + 2);
}

int parse_request(int sockfd, char *recv_buf, req_pack *rp)
{
	int offset;
	offset = parse_start_line(sockfd, recv_buf, rp);
	if (offset == -1) {
		return FAILED;
	}

	return OK;
}

void handle_request(void *arg)
{
	int cli_fd = *(int *)arg;
	char buf[BUFF_SIZE];
	int req_len = 0;
	int recv_len = 0;
	char recv_buf[BUFF_SIZE];
	int i = 0;
	req_pack *rp = NULL;
	rp = (req_pack *)malloc(sizeof(req_pack));
	memset(rp, 0, sizeof(req_pack));


	/* 调用recv函数接收客户端发来的请求信息 */
	recv_len = recv(cli_fd, recv_buf, BUFF_SIZE, 0);
	if (recv_len <= 0) {
		return;
	}
	/* 解析请求 */
	req_len = parse_request(cli_fd, recv_buf, rp);

	if (req_len == FAILED) {
		return;
	}

	if (rp->url == NULL || rp->method == NULL) {
		perror("empty url or method");
		exit(-1);
	}

	if (strcasecmp(rp->method, "POST") == 0) {
		/*process_post(cli_fd);*/
	} else {
		process_get(cli_fd, rp);
	}

	free(rp);
	rp = NULL;

	close(cli_fd);
}

int startup()
{
	int server_fd = -1;

	u_short port = PORT;
	struct sockaddr_in server_addr;

	/* 创建一个socket */
	server_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (server_fd == -1) {
		perror("socket");
		exit(-1);
	}
	memset(&server_addr, 0, sizeof(server_addr));
	/* 初始化sockaddr_in结构体,设置端口,IP,和TCP/IP协议族等信息 */
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(PORT);
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	int on = 1;
	if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)) <
	    0) {
		perror("setsockopt");
		exit(-1);
	}

	/* 把套接字地址结构绑定到套接字 */
	if (bind(server_fd, (struct sockaddr *)&server_addr,
		 sizeof(server_addr)) < 0) {
		perror("bind");
		exit(-1);
	}

	/* 启动socket监听请求,开始等待客户端发来的请求 */
	if (listen(server_fd, QUEUE_MAX_COUNT) < 0) {
		perror("listen");
		exit(-1);
	}

	printf("http server running on port %d\n", port);

	return server_fd;
}

int main()
{
	/* 定义server和client的文件描述符 */
	int server_fd = -1;
	struct sockaddr_in client_addr;
	char recv_buf[BUFF_SIZE];
	int recv_len = 0;
	socklen_t client_addr_len = sizeof(client_addr);
	int epoll_fd = 0;
	struct epoll_event event, *server_events;

	server_fd = startup();

	// 创建epoll监听事件
	epoll_fd = epoll_create(EPOLL_MAX_NUM);
	if (epoll_fd < 0) {
		perror("epoll create");
		exit(-1);
	}

	event.events = EPOLLIN;
	event.data.fd = server_fd;

	// 创建epoll控制器
	if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) < 0) {
		perror("epoll ctl");
		exit(-1);
	}

	server_events = malloc(sizeof(struct epoll_event) * EPOLL_MAX_NUM);
	int err = 0;
	pthread_t t_id;
	while (1) {
		// 等待事件到来
		int active_event_cnt =
		    epoll_wait(epoll_fd, server_events, EPOLL_MAX_NUM, -1);
		int i = 0;
		for (i = 0; i < active_event_cnt; i++) {
			// 如果是当前监听的事件
			if (server_events[i].data.fd == server_fd) {
				int client_fd1 = accept(
				    server_fd, (struct sockaddr *)&client_addr,
				    &client_addr_len);
				if (client_fd1 < 0) {
					perror("accept");
					exit(-1);
				}

				char ip[20];
				printf("new connection[%s:%d]\n",
				       inet_ntop(AF_INET, &client_addr.sin_addr,
						 ip, sizeof(ip)),
				       ntohs(client_addr.sin_port));
				printf("client fd: %d\n", client_fd1);
				event.events = EPOLLIN | EPOLLET;
				event.data.fd = client_fd1;
				epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd1,
					  &event);
			} else if (server_events[i].events & EPOLLIN) {
				int *client_fd = (int *)malloc(sizeof(int));
				*client_fd = server_events[i].data.fd;
				err = pthread_create(&t_id, NULL,
						     (void *)handle_request,
						     (void *)client_fd);
				if (err != 0) {
					perror("thread create");
				}
				pthread_detach(t_id);
			} else if (server_events[i].events & EPOLLOUT) {
				printf("EPOLLOUT\n");
			}
		}
	}

	close(server_fd);

	return 0;
}

makefile如下

server_obj = server.o

CFLAGS = -g

LIBS = -lpthread #-lsocket

CC = gcc

server: $(server_obj)
	$(CC) $(server_obj) $(LIBS)-o server
	./server

server.o: server.c
	$(CC) $(CFLAGS) -c server.c


.PHONY: clean
clean:
	rm -rf $(server_obj) $(client_obj) server

http-client

使用浏览器访问上述构建的server,可解析出来对应的打印

注:该demo仅仅是用于模拟http-server是如何工作的,敬请参考
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值