http协议是我们经常会用到的一个协议,比如浏览一个网站的时候,就会用到,http://www.xxx.xxx 这样的形式,有些时候不输入http就默认补充上,也有些是https,是针对http的一个升级版,是加密的,http是明文传输,在安全性上是有问题的。
今天就用c语言实现一个简单的http server,作为server就要监听来自客户端的访问,访问的内容同样也要回传给客户端。那么就可以用socket去实现。通过socket去传输超文本协议的内容,再通过浏览器去显示内容就可以了,这里用最简单的方式去实现,其中http协议得有头部,然后就是要有内容,如果没有http头的话,那就单纯是内容,就是普通文本了。待会给大家测试一下。
#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
char *read_file(char *filename, char *outstr)
{
char str[1024*1024] = {0};
if (!filename || !outstr)
{
printf("input error\n");
return NULL;
}
FILE *fp = NULL;
fp = fopen(filename, "r");
if(!fp)
{
return NULL;
}
while( fgets(str, 1024*1024, fp) )
{
strcat(outstr,str);
memset(str, 0, 1024*1024);
}
fclose(fp);
return outstr;
}
int main(int argc, char *argv[])
{
int server_sockfd;
int client_sockfd;
int len,pid;
struct sockaddr_in server_addr;
struct sockaddr_in remote_addr;
int sin_size;
char buf[BUFSIZ];
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(8888);
if((server_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("socket failed\n");
exit(0);
}
if (bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0)
{
printf("bind failed\n");
exit(0);
}
listen(server_sockfd, 5);
sin_size = sizeof(struct sockaddr_in);
while(1)
{
client_sockfd = accept(server_sockfd, (struct sockaddr *) &remote_addr, &sin_size);
if (client_sockfd < 0)
{
error("failed on accept");
}
pid = fork();
if (pid < 0)
{
error("failed on fork");
}
if (pid == 0)
{
close(server_sockfd);
char header[] = "HTTP/1.0 200 OK\r\n\r\n";
char html[1024*1024*10] = {0};
recv(client_sockfd, buf, BUFSIZ, 0);
printf("%s\n", buf);
read_file("./baidu.html", html);
send(client_sockfd,header,strlen(header),0);
send(client_sockfd, html, strlen(html), 0);
close(client_sockfd);
exit(0);
}
close(client_sockfd);
}
close(server_sockfd);
return 0;
}
以上的代码向客户端发送的是百度首页的源码,直接右键查看源码,然后复制下来,保存起来。
向上图一样,这里好像不能传文件,随便找个html文件就好了。然后我们编译一下,运行。因为我绑定的是8888端口,所以web访问的时候加上端口。
不知道为啥显示成这样了,可能那个文件有点乱码吧,不懂前端先不管。原理大概就是这么原理,但是嗯,这就是五毛钱的百度,可以在里面搜索,跳转,以后别人给你两千块钱让你做个百度就这么做就好了,哈哈哈。把后台的打印也放上来:
会有http的头,这里如果我不给客户端返回http的头部的话,只传文本回去,看看会出现什么情况。
把发送头部注释掉,看看会发生什么。
就是我们文本的内容,所以头部还是很关键的,这是协议的标识,否则真的只是普通socket加上普通的流了。
我们平时使用的httpserver包括嵌入式常用的都是专门的web服务器来做http服务器,如经典的boa,nignx等等。配合cgi都会有比较好的效果。如果你不怕麻烦,也可以自己实现,放到公网服务器上,做个自己的网站,考虑并发也是一件很酷的事情。