搭建内网服务器

luogu链接

正文

// httpServer.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include<windows.h>
#include<io.h>
#include<bits/stdc++.h>
//要使用网络编程,要包含系统给我们提供的头文件
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
void sendHtml(SOCKET clifd, const char* filePath);
void notFound404(SOCKET clifd);
void notFound403(SOCKET clifd);
//输出错误代码,并返回输出码
void error_die(const char* str) {
    printf("[hint]%s failed:%d", str,WSAGetLastError());//获取错误码
    exit(-1);
}
//初始化
void initSocket() {
    // 参数1.指定socket版本 参数2.是一个传出参数
    WORD version = MAKEWORD(2, 2);
    WSADATA wsadata;
    if (0 != WSAStartup(version, &wsadata)) {
        error_die("WSAStartup");
    }
}
SOCKET listenClient(){
    //2.创建socket
    //参数1.指定IP协议 ipv4(AF_INET) ipv6(AF_INET6)
    //参数2.数据传输格式,常见的有两种,流式传输和数据报传输 
    //参数3.传输协议,                   TCP    和    UDP
    SOCKET serfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (serfd == INVALID_SOCKET) {
        error_die("socket");
    }
    //3.绑定IP地址和端口号
    //参数1.指定的socket
    //参数2.IP地址和端口号
    //参数3.
    struct sockaddr_in serAddr;
    /*
    typedef struct sockaddr_in {
        USHORT sin_port;
        IN_ADDR sin_addr;
        CHAR sin_zero[8];
    } SOCKADDR_IN, *PSOCKADDR_IN;
    */
    serAddr.sin_family = AF_INET;//必须和创建socket的时候一样
    //大端存储--一般网络和小端存储--一般计算机,htons把本地字节序转为网络字节序
    serAddr.sin_port = htons(80);       //[0-65535) 0-1024是系统保留端口号,一般不用,80是http服务器专用
    serAddr.sin_addr.S_un.S_addr = INADDR_ANY;//绑定本机任意服务器
    if (SOCKET_ERROR == bind(serfd, (struct sockaddr*)&serAddr, sizeof(serAddr))) {
        error_die("bind");
    }
    //4.监听
    listen(serfd, 10);
    return serfd;
}
void accept_request(SOCKET clifd) {
    //从clifd接受数据
    char recvBuf[1024] = "";
    if (recv(clifd, recvBuf, sizeof(recvBuf), 0)<=0) {
        error_die("recv offline");
    }
	SYSTEMTIME st;//定义本地时间变量,该变量为结构体
	GetLocalTime(&st);//获取本地时间函数,参数为时间变量指针
	cout<<"time:"<<st.wYear<<"年"<<st.wMonth<<"月"<<st.wDay<<"日"<<st.wHour<<"时"<<st.wMinute<<"分"<<st.wSecond<<"秒"<<endl;
    std::cout<<"recvBuf:";
	cout<<recvBuf<<std::endl;
    fstream r1;//保存日志
    r1.open("日志.txt",ios::app);
    r1<<"have a new connect...\ntime:"<<st.wYear<<"年"<<st.wMonth<<"月"<<st.wDay<<"日"<<st.wHour<<"时"<<st.wMinute<<"分"<<st.wSecond<<"秒"<<'\n'<<recvBuf<<endl;
    fstream cache;
	cache.open("cache.txt",ios::out);
    cache<<recvBuf;
    cache.close();
    cache.clear();
    cache.open("cache.txt");
    string a;
    getline(cache,a);
	//直接给客户端发送文本
	char filePath[128] = "";
	string b="";
	for(int i=4;i<a.size()-9;i++){
		b+=a[i];
	}
	cache.close();
	cache.clear();
	//选择一个网页发送
	strcpy(filePath,&("htmlFiles"+b)[0]);
	//判断文件是否存在
	if (access(filePath,0)==0) {//0代表文件是否存在 如果存在返回0,否则返回-1
	    //发送网页
	    sendHtml(clifd, filePath);
	}
	else {
	    //发送404 not found网页
	    notFound404(clifd);
	}
}
void sendHtml(SOCKET clifd, const char * filePath) {
    FILE* pr = fopen(filePath, "r");
    if (pr==NULL) {
        //error_die("fopen");
        notFound403(clifd);
    }
    char data[1024] = "";
    do {
        fgets(data, 1024, pr);
        send(clifd, data, strlen(data), 0);
    } while (!feof(pr));
    fclose(pr);
}
void notFound404(SOCKET clifd) {
    //发送错误
    char sendData[1024] = "<html><body><p>hjsxhst2022的服务器</p></body></html>";
    send(clifd, sendData, strlen(sendData), 0);
    char sendBuf[1024];
    sprintf(sendBuf,"HTTP/1.0 404 爆炸啦~\r\n");
    send(clifd, sendBuf, strlen(sendBuf), 0);
}
void notFound403(SOCKET clifd) {
    //发送错误
    char sendData[1024] = "<html><body><p>hjsxhst2022的服务器</p></body></html>";
    send(clifd, sendData, strlen(sendData), 0);
    char sendBuf[1024];
    sprintf(sendBuf,"HTTP/1.0 403 爆炸啦~\r\n");
    send(clifd, sendBuf, strlen(sendBuf), 0);
}
int main()
{
    //1.初始化网络库wsa windows socket ansyc->windows异步套接字
    initSocket();
    SOCKET serfd = listenClient();
    printf("hjsxhst2022的http服务器!\n");
    //5.接收链接
    struct sockaddr_in cliAddr;
    int len = sizeof(cliAddr);
    while (1) {
        SOCKET clifd = accept(serfd, (struct sockaddr*)&cliAddr, &len);//阻塞的
        //SOCKET clifd = accept(serfd, NULL, NULL);
        if (clifd == INVALID_SOCKET) {
            error_die("accept");
        }
        printf("have a new connect...\n");
        //6.处理链接请求
        //直接给客户端发送文本
        //char sendData[1024] = "<html><body><h1>zhinen丶</h1></body></html>";
        //send(clifd, sendData, strlen(sendData), 0);
        accept_request(clifd);
        closesocket(clifd);//发送完直接关闭,http是无连接的
    }
    //7.关闭链接,清理网络库
    closesocket(serfd);
    WSACleanup();
    return 0;
}


socket 做的,仅在内网可以访问。这里使用的是 http 协议的 $80$ 端口,如果想在外网访问的话要做一下内网穿透。上面的代码用 dev-c++ 就可以编译,只需要在工具-编译选项-编译时加入如下命令中加入:-std=c++14 -lws2_32就可以编译了。网页文件在绝对路径下的 htmlFiles 目录中保存,现在实现了可以通过路径访问页面和记录日志的功能。更新了403炸。

posted @ 2023-08-18 17:03  hjsxhst2022  阅读(158)  评论(0编辑  收藏  举报