一个简单的HTTP服务器(多线程)
=============================================================================================
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_INIT_SIZE 512
enum {
mickey_reading_header_stage,
mickey_writing_header_stage,
mickey_writing_body_stage,
mickey_closing_stage
};
enum {
mickey_http_ok,
mickey_http_notfound,
mickey_http_error
};
enum {
mickey_method_get,
mickey_method_head,
mickey_method_unknow
};
typedef struct {
char
*buff;
int
size;
int
free;
} mickey_buffer_t;
typedef struct {
int
sock;
mickey_buffer_t *request;
mickey_buffer_t *response;
int
keepalive;
int
method;
mickey_buffer_t *uri;
int
status;
int
stage;
FILE
*handle;
} mickey_connection_t;
static int srv_sock;
mickey_buffer_t *mickey_buffer_new() {
mickey_buffer_t *object;
object =
malloc(sizeof(*object));
if (object)
{
object->buff = malloc(BUFFER_INIT_SIZE + 1);
if (!object->buff) {
free(object);
return NULL;
}
object->size = BUFFER_INIT_SIZE;
object->free = BUFFER_INIT_SIZE;
}
return
object;
}
int mickey_buffer_append_length(mickey_buffer_t *buf, void
*data, int length) {
int lack,
need = 0;
char
*temp;
if (length
> buf->free) {
lack = length - buf->free;
while (need < lack)
need += BUFFER_INIT_SIZE;
temp = realloc(buf->buff, buf->size +
need + 1);
if (!temp)
return -1;
buf->buff = temp;
buf->size += need;
buf->free += need;
}
memcpy(buf->buff + (buf->size -
buf->free), data, length);
buf->free -= length;
buf->buff[buf->size -
buf->free] = '\0';
return
0;
}
int mickey_buffer_append(mickey_buffer_t *buf, void *data)
{
return
mickey_buffer_append_length(buf, data, strlen((char *)data));
}
int mickey_buffer_find_string(mickey_buffer_t *buf, char *str)
{
int idx =
buf->size - buf->free;
int slen =
strlen(str);
int i;
for (i = 0;
i < idx; i++) {
if (idx - i >= slen) {
if (!memcmp(buf->buff + i, str, slen)) return
1;
} else {
break;
}
}
return
0;
}
int mickey_buffer_length(mickey_buffer_t *buf) {
return
buf->size - buf->free;
}
void mickey_buffer_print(mickey_buffer_t *buf) {
fprintf(stderr, "%s", buf->buff);
}
void mickey_buffer_clean(mickey_buffer_t *buf) {
buf->free = buf->size;
}
void mickey_buffer_free(mickey_buffer_t *buf) {
if
(!buf)
return;
if
(buf->buff)
free(buf->buff);
free(buf);
}
int mickey_header_finish(mickey_connection_t *conn) {
int end =
conn->request->size -
conn->request->free;
if
(conn->request->buff[end - 1] == '\n'
&&
conn->request->buff[end - 2] == '\r'
&&
conn->request->buff[end - 3] == '\n'
&&
conn->request->buff[end - 4] ==
'\r')
return 1;
return
0;
}
void mickey_parse_header(mickey_connection_t *conn) {
char
*eol;
char
method[16], uri[256], protocol[32];
eol =
strchr(conn->request->buff,
'\n');
if (eol ==
NULL) {
conn->stage = mickey_closing_stage;
return;
}
if (*(eol-1)
== '\r')
*(eol-1) = '\0';
*eol =
'\0';
sscanf(conn->request->buff, "s %6s
2s", method, uri, protocol);
if
(!strcmp(method, "GET")) {
conn->method = mickey_method_get;
} else if
(!strcmp(method, "HEAD")) {
conn->method = mickey_method_head;
} else
{
conn->method = mickey_method_unknow;
}
mickey_buffer_append(conn->uri, ".");
mickey_buffer_append(conn->uri, uri);
if
(mickey_buffer_find_string(conn->uri, "..")) {
fprintf(stderr, "[x] mickey found connection header exists
(..)\n");
conn->stage = mickey_closing_stage;
}
}
void connection_reading_header(mickey_connection_t *conn)
{
char
buff[1024];
int
nrecv;
nrecv =
read(conn->sock, buff, 1024);
if (nrecv
> 0) {
mickey_buffer_append_length(conn->request, buff,
nrecv);
if (mickey_header_finish(conn)) {
mickey_parse_header(conn);
conn->stage = mickey_writing_header_stage;
}
} else
{
fprintf(stderr, "[x] mickey cannot read data from
connection.\n");
conn->stage = mickey_closing_stage;
}
}
void connection_make_header(mickey_connection_t *conn) {
struct stat
stat_buf;
if
(stat(conn->uri->buff,
&stat_buf) == -1) {
conn->status = mickey_http_notfound;
mickey_buffer_append(conn->response, "HTTP/1.0 404
Not Found\r\n");
} else
{
if (S_ISDIR(stat_buf.st_mode)) {
mickey_buffer_append(conn->uri, "index.html");
if (stat(conn->uri->buff,
&stat_buf) == -1) {
conn->status = mickey_http_notfound;
mickey_buffer_append(conn->response, "HTTP/1.0 404
Not Found\r\n");
} else {
char content_length[256];
conn->handle =
fopen(conn->uri->buff, "r");
if (!conn->handle) {
mickey_buffer_append(conn->response, "HTTP/1.0 500
Internal Server Error\r\n");
} else {
mickey_buffer_append(conn->response, "HTTP/1.0 200
OK\r\n");
sprintf(content_length, "Content-Length: %d\r\n",
stat_buf.st_size);
mickey_buffer_append(conn->response,
content_length);
}
}
} else if (S_ISREG(stat_buf.st_mode)) {
char content_length[256];
conn->handle =
fopen(conn->uri->buff, "r");
if (!conn->handle) {
mickey_buffer_append(conn->response, "HTTP/1.0 500
Internal Server Error\r\n");
} else {
mickey_buffer_append(conn->response, "HTTP/1.0 200
OK\r\n");
sprintf(content_length, "Content-Length: %d\r\n",
stat_buf.st_size);
mickey_buffer_append(conn->response,
content_length);
}
} else {
mickey_buffer_append(conn->response, "HTTP/1.0 500
Internal Server Error\r\n");
}
}
mickey_buffer_append(conn->response, "\r\n");
//mickey_buffer_print(conn->response);
}
void connection_send_header(mickey_connection_t *conn) {
int bytes =
mickey_buffer_length(conn->response);
int nsend, i
= 0;
while (i
< bytes) {
nsend = write(conn->sock,
conn->response->buff + i, bytes -
i);
if (nsend > 0) {
i += nsend;
} else {
sleep(1);
continue;
}
}
conn->stage = mickey_writing_body_stage;
}
void connection_send_body(mickey_connection_t *conn) {
char
buff[1024];
int
bytes;
if
(!conn->handle) {
conn->stage = mickey_closing_stage;
return;
}
while
(!feof(conn->handle)) {
int ws = 0;
int hs = 0;
fread(buff, 1024, 1, conn->handle);
bytes = strlen(buff);
while (ws < bytes) {
hs = write(conn->sock, buff + ws, bytes - ws);
if (hs > 0) {
ws += hs;
} else {
sleep(1);
continue;
}
}
}
fclose(conn->handle);
conn->stage = mickey_closing_stage;
}
mickey_connection_t *connection_new(int sock) {
mickey_connection_t *conn;
conn =
malloc(sizeof(*conn));
if (conn)
{
conn->sock
= sock;
conn->keepalive = 0;
conn->stage
= mickey_reading_header_stage;
conn->status
= mickey_http_ok;
conn->request =
mickey_buffer_new();
conn->response =
mickey_buffer_new();
conn->uri
= mickey_buffer_new();
if (!conn->request || !conn->response
|| !conn->uri) {
mickey_buffer_free(conn->request);
mickey_buffer_free(conn->response);
mickey_buffer_free(conn->uri);
free(conn);
return NULL;
}
return conn;
}
return
NULL;
}
void connection_exit(mickey_connection_t *conn) {
if
(conn->request)
mickey_buffer_free(conn->request);
if
(conn->response)
mickey_buffer_free(conn->response);
if
(conn->uri)
mickey_buffer_free(conn->uri);
free(conn);
}
void *connection_thread_entrance(void *arg) {
mickey_connection_t *conn = (mickey_connection_t *)arg;
pthread_detach(pthread_self());
fprintf(stderr, "[+] === mickey thread working ===\n");
while (1)
{
switch (conn->stage) {
case mickey_reading_header_stage:
connection_reading_header(conn);
break;
case mickey_writing_header_stage:
connection_make_header(conn);
connection_send_header(conn);
break;
case mickey_writing_body_stage:
connection_send_body(conn);
break;
case mickey_closing_stage:
close(conn->sock);
connection_exit(conn);
goto THREAD_CLOSING;
break;
}
}
THREAD_CLOSING:
fprintf(stderr, "[-] === mickey thread closing ===\n");
pthread_exit(NULL);
}
int initialize_server() {
struct
sockaddr_in addr;
struct
linger ling = {0, 0};
int flags =
1;
srv_sock =
socket(AF_INET, SOCK_STREAM, 0);
if (srv_sock
== -1)
return -1;
setsockopt(srv_sock, SOL_SOCKET, SO_REUSEADDR,
&flags, sizeof(flags));
setsockopt(srv_sock, SOL_SOCKET, SO_KEEPALIVE,
&flags, sizeof(flags));
setsockopt(srv_sock, SOL_SOCKET, SO_LINGER, &ling,
sizeof(ling));
#if !defined(TCP_NOPUSH)
setsockopt(srv_sock, IPPROTO_TCP, TCP_NODELAY,
&flags, sizeof(flags));
#endif
addr.sin_family = AF_INET;
addr.sin_port = htons(8080);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if
(bind(srv_sock, (struct sockaddr *) &addr,
sizeof(addr)) == -1)
return -1;
if
(listen(srv_sock, 1024) == -1)
return -1;
return
srv_sock;
}
void socket_accept_connection() {
int
new_sock;
socklen_t
len;
struct
sockaddr addr;
mickey_connection_t *new_conn;
pthread_t
tid;
while (1)
{
new_sock = accept(srv_sock, &addr,
&len);
if (new_sock == -1) {
if (errno != EAGAIN && errno !=
EWOULDBLOCK) {
continue;
}
goto ERROR_FLAG;
}
new_conn = connection_new(new_sock);
if (!new_conn) {
fprintf(stderr, "[x] mickey not enough momery.\n");
close(new_sock);
goto ERROR_FLAG;
}
pthread_create(&tid, NULL,
connection_thread_entrance, new_conn);
}
ERROR_FLAG:
fprintf(stderr, "[x] mickey cannot accept client
connection.\n");
return;
}
int main(int argc, char **argv) {
chdir("./");
if
(initialize_server() == -1) {
fprintf(stderr, "[x] mickey initialize failed.\n");
exit(1);
}
socket_accept_connection();
exit(0);
}
0
喜欢
0
赠金笔
一个简单的HTTP服务器(多线程)的更多相关文章
- 自己动手模拟开发一个简单的Web服务器
开篇:每当我们将开发好的ASP.NET网站部署到IIS服务器中,在浏览器正常浏览页面时,可曾想过Web服务器是怎么工作的,其原理是什么?“纸上得来终觉浅,绝知此事要躬行”,于是我们自己模拟一个简单的W ...
- 响应式编程笔记三:一个简单的HTTP服务器
# 响应式编程笔记三:一个简单的HTTP服务器 本文我们将继续前面的学习,但将更多的注意力放在用例和编写实际能用的代码上面,而非基本的APIs学习. 我们会看到Reactive是一个有用的抽象 - 对 ...
- 使用纯php构建一个简单的PHP服务器
使用原生PHP构建一个简单的PHPWeb服务器 1.目录机构 webserver --src -- Response.php -- Server.php -- Request.php -- vendo ...
- 一个简单的web服务器
写在前面 新的一年了,新的开始,打算重新看一遍asp.net本质论这本书,再重新认识一下,查漏补缺,认认真真的过一遍. 一个简单的web服务器 首先需要引入命名空间: System.Net,关于网络编 ...
- [置顶] 在Ubuntu下实现一个简单的Web服务器
要求: 实现一个简单的Web服务器,当服务器启动时要读取配置文件的路径.如果浏览器请求的文件是可执行的则称为CGI程序,服务器并不是将这个文件发给浏览器,而是在服务器端执行这个程序,将它的标准输出发给 ...
- Tomcat剖析(二):一个简单的Servlet服务器
Tomcat剖析(二):一个简单的Servlet服务器 1. Tomcat剖析(一):一个简单的Web服务器 2. Tomcat剖析(二):一个简单的Servlet服务器 3. Tomcat剖析(三) ...
- Tomcat剖析(一):一个简单的Web服务器
Tomcat剖析(一):一个简单的Web服务器 1. Tomcat剖析(一):一个简单的Web服务器 2. Tomcat剖析(二):一个简单的Servlet服务器 3. Tomcat剖析(三):连接器 ...
- 自己模拟的一个简单的web服务器
首先我为大家推荐一本书:How Tomcat Works.这本书讲的很详细的,虽然实际开发中我们并不会自己去写一个tomcat,但是对于了解Tomcat是如何工作的还是很有必要的. Servlet容器 ...
- java实现一个简单的Web服务器
注:本段内容来源于<JAVA 实现 简单的 HTTP服务器> 1. HTTP所有状态码 状态码 状态码英文名称 中文描述 100 Continue 继续.客户端应继续其请求 101 Swi ...
随机推荐
- MsSqlServer bak文件数据导入
MsSqlServer bak文件数据导入 第一步首先在你的数据库中建立一个空数据库 选中新建的数据库 鼠标右键 任务 还原 数据库 这个时候会弹出这种一个框 之后选择原设备 会弹出 点击加入 找到 ...
- Serialize a Binary Tree or a General Tree
For a binary tree, preorder traversal may be enough. For example, _ / \ / / \ 50 ...
- Servlet的学习之Request请求对象(3)
本篇接上一篇,将Servlet中的HttpServletRequest对象获取RequestDispatcher对象后能进行的[转发]forward功能和[包含]include功能介绍完. 首先来看R ...
- DRP分销系统总结
上个月看完的分销系统的视频,用了漫长的时间看这个项目视频,能安慰自己的是不光是看视频了,还做了很多自己想做的事情,比如驾照拿下来了,比如参加了一些考试,比如讲了一些课程等等.把这个系统的总结总算是补上 ...
- DFA最小化 -- Hopcroft算法 Python实现
wiki 伪代码看上去一直以为怪.发现葡萄牙语和俄罗斯语那里的 if 推断都还缺少一个条件. 国内的资料比較少.这几份学习资料不错.比我稀里糊涂的思路要好,分享下: http://www.liafa. ...
- java中文排序问题(转)
在Java中,对一个数组或列表(在本文中统称为集合)中的元素排序,是一个很经常的事情.好在Sun公司在Java库中实现了大部分功能.如果集合中的元素实现了Comparable接口,调用以下的静态(st ...
- 修改Tabhost样式和字体大小和居中显示
有时候我们的tabhost并不需要贴图,所以这个时候就必须把文字居中显示和设置大小了,代码如下 setContentView(R.layout.home_vzo_tabhost); ...
- EasyUI初体验--右键弹框
在C/S中可能非常easy实现右键弹框,但在B/S中直到今天我才搞定,小小得瑟一下.只一个html页面,导入相关的Easy-UI类库就能搞定,Easy-UI类库下载地址 <!DOCTYPE ht ...
- Hbase集群环境搭建
Hbase数据库依赖 Hadoop和zookeeper,所以,安装Hbase之前,需要先把zookeeper集群搭建好.(当然,Hbase有内建的zookeeper,不过不建议使用).Hbase配置上 ...
- - Shell - sort处理大文件(页 1) - ChinaUnix.net
- Shell - sort处理大文件(页 1) - ChinaUnix.net sort处理大文件