c++简单Web服务器的实现

整体思路:

1.建立一个socket。
2.创建结构体地址,初始化这个地址为本机地址(“127.0.0.1”)。
3.然后把socket和这个地址绑定。(bind函数),因为采用TCP形式通信,所以绑定后为,ip地址+端口号,这里设置的是8888。
4.上面创建好的地址是我收东西的地址,我开始监听这个端口(listen)。
5.while(1)循环监听,创建一个新的地址,放accept里面可以显示地址来自哪里,这里accept相当于接收到了传过来的socket。
6.返回信息,有很多返回信息的方法,有read,write什么的,我初学觉得recv和send还是比较好用的。一个接收客户端传来的信息,一个向发送方发送信息。
这里有关于这两个函数的详解:here
7.这个程序放在linux运行,运行成功后,打开浏览器访问本机地址。
http://localhost:8888/

/*
	实现一个最简单的Web服务器:
	用本机实现。ip:127.0.0.1
	服务器程序接收到访问请求,然后返回给他一个网页open函数。
*/
/*
	实现一个最简单的Web服务器:
	用本机实现。ip:127.0.0.1
	服务器程序接收到访问请求,然后返回给他一个网页open函数。
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#include<netinet/in.h>
#include<arpa/inet.h> 
#include<sys/socket.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/sendfile.h>
using namespace std;
#define MYPORT 8888
int main(){
	struct sockaddr_in ads; //设置地址
	bzero(&ads, sizeof(ads));
	ads.sin_family = AF_INET; //ipv4形式
	ads.sin_port = htons(MYPORT); //主机字节序转换成网络字节序 其实就是高位和低位的反转
	//ads.sin_addr.s_addr = inet_addr("127.0.0.1"); //从哪个ip地址来的
	ads.sin_addr.s_addr = htonl(INADDR_ANY); //从哪个ip地址来的
	int sid = socket(AF_INET,SOCK_STREAM,0);  //设置套接字
	assert(sid>=0);
	cout << "socket successful" << endl;

	int bind_ok = bind(sid,(struct sockaddr*)&ads,sizeof(struct sockaddr));
	//绑定了ip地址和套接字  那么就可以接收了
	assert(bind_ok != -1);
	int listen_ok=listen(sid, 10); //开始监听是否有连接
	assert(listen_ok !=-1);
	cout << "listen successful" << endl;
	while (1) {   //不断执行  你发我还会执行
		struct sockaddr_in client;
		socklen_t client_addrlength = sizeof(client);
		int connfd = accept(sid, (struct sockaddr*)&client, &client_addrlength);
		//一直接收,那个地址存储接收到的信息来自的地址
		if (connfd < 0){
			printf("errno\n");
		}
		else{
			char res[1025];
			string now = "wcx";
			recv(connfd,res,1024,0);
			//收到的存储在这里面  在这里接收信息
			printf("susuccesseful!\n");
			//char buf[520] = "HTTP/1.1 200 ok\r\nconnection: close\r\n\r\n";//HTTP响应
			//int s = send(connfd, buf, strlen(buf), 0);//发送响应
			send(connfd,now.c_str(),strlen(now.c_str()),0);
			//int fd = open("hello.html", O_RDONLY);//消息体
			/*
			o_rdonly read only 只读
			o_wronly write only 只写
			o_rdwr read write 可读可写
			o_trunc 若文件存在则长度被截为0(属性不变)
			*/
			//sendfile(connfd, fd, NULL, 2500);//零拷贝发送消息体
			close(connfd);
		}
	}
	return 0;
}

运行结果:

正在监听:
在这里插入图片描述访问本地端口
在这里插入图片描述
也可以用curl直接访问,这是个url工具,可以在终端直接获取对应url的信息:

在这里插入图片描述访问成功。

现在我们尝试传送一个html文件给客户端

/*
	实现一个最简单的Web服务器:
	用本机实现。ip:127.0.0.1
	服务器程序接收到访问请求,然后返回给他一个网页open函数。
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#include<netinet/in.h>
#include<arpa/inet.h> 
#include<sys/socket.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/sendfile.h>
using namespace std;
#define MYPORT 8888
int main(){
	struct sockaddr_in ads; //设置地址
	bzero(&ads, sizeof(ads));
	ads.sin_family = AF_INET; //ipv4形式
	ads.sin_port = htons(MYPORT); //主机字节序转换成网络字节序 其实就是高位和低位的反转
	//ads.sin_addr.s_addr = inet_addr("127.0.0.1"); //从哪个ip地址来的
	ads.sin_addr.s_addr = htonl(INADDR_ANY); //从哪个ip地址来的
	int sid = socket(AF_INET,SOCK_STREAM,0);  //设置套接字
	assert(sid>=0);
	cout << "socket successful" << endl;

	int bind_ok = bind(sid,(struct sockaddr*)&ads,sizeof(struct sockaddr));
	//绑定了ip地址和套接字  那么就可以接收了
	assert(bind_ok != -1);
	int listen_ok=listen(sid, 10); //开始监听是否有连接
	assert(listen_ok !=-1);
	cout << "listen successful" << endl;
	while (1) {   //不断执行  你发我还会执行
		struct sockaddr_in client;
		socklen_t client_addrlength = sizeof(client);
		int connfd = accept(sid, (struct sockaddr*)&client, &client_addrlength);
		//一直接收,那个地址存储接收到的信息来自的地址
		if (connfd < 0){
			printf("errno\n");
		}
		else{
			char res[1025];
			string now = "wcx";
			recv(connfd,res,1024,0);
			//收到的存储在这里面  在这里接收信息
			printf("susuccesseful!\n");
			char buf[520] = "HTTP/1.1 200 ok\r\nconnection: close\r\n\r\n";//HTTP响应
			int s = send(connfd, buf, strlen(buf), 0);//发送响应
			//send(connfd,now.c_str(),strlen(now.c_str()),0);
			int fd = open("hello.html", O_RDONLY);//消息体 当然也可以写别的如txt文件
			/*
			o_rdonly read only 只读
			o_wronly write only 只写
			o_rdwr read write 可读可写
			o_trunc 若文件存在则长度被截为0(属性不变)
			*/
			sendfile(connfd, fd, NULL, 2500);//零拷贝发送消息体  这里改变了
			close(connfd);
		}
	}
	return 0;
}

和上面的程序差别只是在发送程序中的open函数和sendfile函数的应用,以及http响应报文,不建立连接可以传送。但是没有明显制定协议,没法解析成html会直接按照文本形式显示,先连接后用http协议可以方便解析html代码(个人理解),主要是建立连接的重要性。
先写好一个简单的html程序:

<html>
    <body bgcolor="blue">
     this is the html.
     <hr>
     <p>hello word! waste young! </p><br>
    </body>
</html>

在这里插入图片描述
和主函数在一个文件夹中,然后剩下的运行步骤和上面一样,如果用网页打开,浏览器会识别html语言:

用浏览器去访问:在这里插入图片描述
用curl去访问(不会识别返回内容):
在这里插入图片描述

参考博客:here

发布了50 篇原创文章 · 获赞 67 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_41033366/article/details/103182963