C++实现简单的HTTP Server

可以参考下典型的http会话,服务器响应由一系列文本指令组成, 并使用 CRLF 分隔,它们被划分为三个不同的块:

  • 第一行是 状态行,包括使用的HTTP协议版本,状态码和一个状态描述(可读描述文本)。
  • 接下来每一行都表示一个HTTP首部,为客户端提供关于所发送数据的一些信息(如类型,数据大小,使用的压缩算法,缓存指示)。与客户端请求的头部块类似,这些HTTP首部组成一个块,并以一个空行结束。
  • 最后一块是数据块,包含了响应的数据(如果有的话)。

具体实现如下代码,收到postman发过来的消息后,将收到的消息显示出来,并回复状态ok的响应,这就完成了一个最简单的http服务器模型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>

int main(void)
{
int fd = socket(PF_INET, SOCK_STREAM, 0);
if (fd == -1) {
printf("create socket error %d\n", errno);
exit(1);
}
int on = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
struct sockaddr_in addr;
addr.sin_family = PF_INET;
addr.sin_port = htons(8081);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(fd, reinterpret_cast<struct sockaddr *>(&addr),
sizeof(addr)) != 0) {
printf("bind socket error %d\n", errno);
switch (errno)
{
case EADDRINUSE:
std::cout << "Address already in use" << std::endl;
break;

default:
break;
}
close(fd);
exit(1);
}
if (listen(fd, 1024) != 0) {
printf("listen socket error %d\n", errno);
close(fd);
exit(1);
}
while(1) {
struct sockaddr_in cli;
int len = sizeof(cli);
int nfd = accept(fd, reinterpret_cast<struct sockaddr *>(&cli),
reinterpret_cast<socklen_t *>(&len));
if(nfd == -1) {
printf("accept socket error %d\n", errno);
close(fd);
exit(1);
}

char buf[1024];
char content[] = "hello http!";
bzero(buf, 1024);
recv(nfd, buf, 1024, 0);
printf("----------------recv msg----------------\n%s\n", buf);
bzero(buf, 1024);
sprintf(buf, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n"
"Content-Type: text/html\r\n\r\n%s", static_cast<int>(strlen(content)), content);
printf("----------------ready to send buf----------------\n%s\n", buf);
if (send(nfd, buf, strlen(buf), 0) == -1) {
printf("write socket error %d\n", errno);
}
if (close(nfd) != 0)
printf("close nfd err: %d\n", errno);
}

if (close(fd) != 0)
printf("close fd err: %d\n", errno);
exit(0);
}

这里写法可以留意一下,将socket建立,绑定监听放在while循环之上,循环里面只要连续的accept就行了,完了之后把accept的fd给close掉,close就是代表主动关闭连接了。
发送http请求
服务器端接收情况
如果你没有下载postman的话,也可以使用curl命令发送请求。
curl发送请求
服务器端接收情况

nephen wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
坚持原创技术分享,您的支持将鼓励我继续创作!