欢迎访问雷泽体育中国历史网!

如何用服务器搭建自己的小我私家网站

时间:2021-09-19 01:22作者:雷泽体育

本文摘要:这篇教程主要是告诉大家如何使用TCP和HTTP协议来完成网站的搭建。首先你需要有C/C++语言基础,且有服务器、客户端观点,如果你相识TCP或者HTTP协议的话,那么将会资助你更快的学会如何搭建小我私家网站。

雷泽体育

这篇教程主要是告诉大家如何使用TCP和HTTP协议来完成网站的搭建。首先你需要有C/C++语言基础,且有服务器、客户端观点,如果你相识TCP或者HTTP协议的话,那么将会资助你更快的学会如何搭建小我私家网站。该服务器使用的Windows中的IOCP模式来举行,我将put代码中最为重要的几个部门1.准备好HTML文件,也就是你所要公布的网页,可以是静态网页也可以是动态网页,为了更好的资助大家入门,我准备了一个最为轻便的html代码如下:<!DOCTYPE html><html lang="ch-ZH"><head> <meta charset="UTF-8"> <title>My Website</title> <link rel="icon" href="img/sad.png"> <link rel="stylesheet" href="index.css"></head><body> <div style="width: 100px;height:100px;"> </div> <span>HelloWorld</span> <div style="background-color: blue; border: 1px solid orange"> Hi.Im david </div></body></html> 123456789101112131415161718192021你可以直接复制该文件并生存为html形式,文件名生存为 index.html。

如果你不关系如何去自己书写代码完成搭建小我私家网站的,请点击这里。2.开始正式的编程。

我假设你有TCP/IP协议的相关知识,故不做太多先容。a)首先我们设置开发情况,如果你使用的VS的话,那么首先你需要几步来完成网络通信的情况搭建1.) 建立项目并打开项目属性。转到 链接器中的输入选项之中:在附加依赖项之中添加 ws2_32.lib; 该库为网络通信库2.) 引入头文件 #include <WinSock2.h> 和 #include<Windows.h>。注意: <Windows.h>必须在<WinSock2.h>之后。

否则会泛起重界说错误b) 建立套接字历程代码#include <WinSock2.h>#include <Windows.h>int main(){WSADATA wsaData; //在Windows之中建立套接字需要使用到的工具HANDLE hComPort;//完成端口CP工具SYSTEM_INFO sysInfo;//获取系统信息WSAEVENT wEvent;//重叠事件/// 关于客户端的信息与io相关的信息一定要是动态分配的。否则在通报给其他线程的时候将会引用原本的地址且无法重新分配新的客户端与io数据LPCLNTINFO pClntInfo;//生存客户端信息LP_IO_DATA pIoData;//生存着io相关的数据SOCKET servSock, clntSock;//服务器与客户端套接字SOCKADDR_IN servAddr, clntAddr;//服务器与客户端地址int clntAddrSz;//客户端地址长度DWORD recvBytes = 0,flag = 0;//吸收的数据巨细和标志int port = 0;//端口号//std::ofstream connectLog("connectLog.txt");//生存客户端毗连信息 //这是一个处置惩罚输入的函数,我们将会在之后讲到。getPortNumber(port);//处置惩罚输入数据并获取端口号。

if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NULL)ErrorMsg("WSAStartup() error");///建立完后端口号。hComPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);GetSystemInfo(&sysInfo);//获取系统信息///建立多个线程来分散IO处置惩罚 for (int i = 0; i < sysInfo.dwNumberOfProcessors; ++i)_beginthreadex(NULL, 0, ClntHandle, (LPVOID)hComPort, 0, NULL);//开始线程处置惩罚。servSock = WSASocket(PF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);//建立重叠套接字///错误处置惩罚if (servSock == INVALID_SOCKET)ErrorMsg("WSASocket() Error");///初始化IP地址和端口号。memset(&servAddr, 0, sizeof(servAddr));servAddr.sin_family = AF_INET;//IPV4协议servAddr.sin_port = htons(port);//小端序转位网路大端序servAddr.sin_addr.s_addr = htonl(INADDR_ANY);//自动获取当地IP地址///绑定服务器地址信息if (bind(servSock, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR)ErrorMsg("bind() error");///监听来自客户端的毗连请求。

500表现最大接代500个客户端同时请求。if (listen(servSock, 500) == SOCKET_ERROR)ErrorMsg("listen() error");clntAddrSz = sizeof(clntAddr);//获取客户端地址结构的巨细std::cout << std::left;//设置左对齐处置惩罚来自客户端的毗连请求while (1){clntSock = accept(servSock, (SOCKADDR*)&clntAddr, &clntAddrSz);wEvent = WSACreateEvent();//存放事件句柄if (clntSock == INVALID_SOCKET)//处置惩罚毗连请求堕落{ErrorMsg("accept() error");}///动态分配内存处置惩罚客户端的毗连pClntInfo = (LPCLNTINFO)malloc(sizeof(CLNTINFO));pClntInfo->hClntSock = clntSock;memcpy(&(pClntInfo->hClntAddr), &clntAddr, clntAddrSz);//复制客户端套接字的地址信息/// 建设套接字到完后端口的毗连CreateIoCompletionPort((HANDLE)clntSock, hComPort, (DWORD)pClntInfo, 0);//通报的四clntInfo整个结构的地址。

之后可以提取出来。/// 动态分配生存着数据传输信息的IO工具pIoData = (LP_IO_DATA)malloc(sizeof(IO_DATA));memset(&(pIoData->overlapped), 0, sizeof(OVERLAPPED));pIoData->wsaBuf.buf = pIoData->buf;pIoData->wsaBuf.len = BUF_SIZE;///吸收客户端信息//当客户端未向服务器发送数据的时候,此时可以判断,客户端需要请求服务器的数据if (WSARecv(clntSock, &(pIoData->wsaBuf), 1, (LPDWORD)&recvBytes, (LPDWORD)&flag, &(pIoData->overlapped), NULL) == SOCKET_ERROR) //注意此处通报的是ioData的整个结构地址{//if (WSAGetLastError() == WSA_IO_PENDING)//数据仍在吸收中//{//std::cout << "数据仍在吸收中..." << std::endl;//}}}closesocket(servSock);WSACleanup();return 0;}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899其中相关数据结构如下:/// 使用了却构指针的地址就是结构首成员地址该点来通报IO端口完成信息typedef struct{SOCKET hClntSock;//客户端套接字SOCKADDR_IN hClntAddr;//客户端IP地址}CLNTINFO, *LPCLNTINFO;//生存着客户端套接字属性typedef struct{OVERLAPPED overlapped;//重叠属性结构WSABUF wsaBuf;//存放缓冲数据的结构 主要存放了 待传输数据的巨细缓和冲地址值char buf[BUF_SIZE];//存放数据的缓冲区}IO_DATA, *LP_IO_DATA;//生存着IO相关的数据12345678910111213之前 提到的getPortNumber函数。使用的C++实现输入,如果你对C语言有相识可以换为C代码模式。

需要注意的是,我的代码为C/C++配合实现。该函数主要是保证用户输入流是正确的。void getPortNumber(int & port){///输入端口号举行监听std::cout << "输入有效的监听端口号:";///确保输入了有效的换行符while (!(std::cin >> port)){std::cin.clear();//将cin中的错误位置位std::cin.ignore(224, 'n');//输入有误时忽略输入流中的缓冲信息.忽略最多224个字符,直到遇到了换行符为止std::cout << "输入的端口号有误,重新输入:";}}12345678910111213接下来需要划分解说在main函数之中挪用的各个函数:/// 建设套接字到完后端口的毗连CreateIoCompletionPort((HANDLE)clntSock, hComPort, (DWORD)pClntInfo, 0);12该函数是一个关键点,主要是将毗连进入的客户端与我们的输入输出完成端口举行绑定。之后该套接字存在事件时,将会转到我们的线程处置惩罚函数之中。

开始吸收来自客户端的请求数据。使用的是重叠IO无阻塞模式。WSARecv(clntSock, &(pIoData->wsaBuf), 1, (LPDWORD)&recvBytes, (LPDWORD)&flag, &(pIoData->overlapped), NULL);1之后每次当客户端发出请求数据,都市在以下函数中处置惩罚unsigned WINAPI ClntHandle(LPVOID cp){DWORD recvBytes = 0, flag = 0;LP_IO_DATA pIoData;//生存着IO工具的数据。挪用WSARecv通报的overlapped结构LPCLNTINFO pClntInfo;//生存客户端的相关信息。

挪用CreateIoCompletionPort通报的第三个参数SOCKET sock;//主要指的是客户端的套接字HANDLE hComPort = (HANDLE)cp;//CP工具while (1){///确定IO完成状态if (!GetQueuedCompletionStatus(hComPort, (LPDWORD)&recvBytes, (LPDWORD)&pClntInfo, (LPOVERLAPPED*)&pIoData, INFINITE)){///在客户端请求数据的历程中如果退出了请求,那么此时该函数则会泛起错误,那么我们需要从错误中恢复过来std::cout << GetLastError() << std::endl;closesocket(pClntInfo->hClntSock);//关闭该套接字。FreeData(&pIoData, &pClntInfo);//释放动态分配的内存。continue;}///插入毗连的客户端 IP地址信息connectCnt[inet_ntoa(pClntInfo->hClntAddr.sin_addr)]++;sock = pClntInfo->hClntSock;pIoData->wsaBuf.buf[recvBytes] = 0;if (recvBytes == 0)//吸收数据为0的时候,此时没有吸收到数据{closesocket(sock);FreeData(&pIoData, &pClntInfo);continue;}//std::cout << "开始吸收客户端信息:" << pIoData->wsaBuf.buf << std::endl;std::string fileName;//文件名std::string compleHead(pIoData->wsaBuf.buf, 100);//部门头信息。

最多获取100个字符char cntType[SMALL_SIZE];int mFind = compleHead.find('/');//查找请求方式int fFind = compleHead.find("HTTP/");//查找文件名///1. 当非GET请求,不剖析。2.当非HTTP/发出的请求不剖析 3.当请求花样错误,不剖析if (mFind == std::string::npos || fFind == std::string::npos|| std::string(compleHead, 0, mFind - 1) != "GET")//请求方式错误{closesocket(sock);ExcptionRequst(&(pClntInfo->hClntAddr), pIoData->wsaBuf.buf);//发生异常毗连 写入文件日志中FreeData(&pIoData, &pClntInfo);continue;}///获取完整文件名 在推断了多种可能的情况下,此种情况下获取文件名应该是宁静的fileName = std::string(compleHead.cbegin() + mFind + 1, compleHead.cbegin() + fFind - 1);if (fileName.empty())//当文件名为空,表现请求的是首页{fileName = "index.html";strcpy_s(cntType, "text/html");}else{char * cs = GetContentType(fileName);if (!cs)//返回的指针为空的时候表现文件不存在后缀{ErrorFile(sock);FreeData(&pIoData, &pClntInfo);continue;}strcpy_s(cntType, cs);//复制请求文件类型}///给客户端发送数据SendDataFile(sock, fileName.c_str(), cntType, pIoData);///释放内存closesocket(sock);FreeData(&pIoData, &pClntInfo);//std::cout << "网页数据发送完成..." << std::endl;}return 0;}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586其中该函数使用到一个很是重要的函数如下:该函数卖力向客户端发送请求文件int SendDataFile(SOCKET sock, const char * fileName, const char *contType, LP_IO_DATA &pIoData){std::ifstream inFile(fileName, std::fstream::binary);//以读的方式打开文件if (!inFile)//请求的文件不存在时{ErrorFile(sock);return -1;}///传输回应头信息//r是回车(Carriage return) n是换行 (New line) char protocol[] = "HTTP/1.1 200 OKrn";//状态char servName[] = "Server: TD Web serverrn";//服务器名字char cntEncode[] = "Content-Encoding: gziprn";//压缩方式char transEncode[] = "Transfer-Encoding: chunkedrn";//传输编码char vary[] = "Vary: Accept-Encodingrn";//接受编码char cntType[SMALL_SIZE];//吸收类型char buf[BUF_SIZE];//数据char end[] = "rn";//竣事符char cntLen[SMALL_SIZE];//内容长度WSABUF wsaBuf;//存放数据缓冲DWORD sendBytes = 0;//WSAEVENT wsaEvent = WSACreateEvent();sprintf_s(cntType, "Content-type:%srn", contType);///向客户端发送回应头信息send(sock, protocol, strlen(protocol), 0);//通报状态行send(sock, servName, strlen(servName), 0);//通报消息头的服务端名send(sock, cntType, strlen(cntType), 0);//通报content-type/// 获取文件长度. 当第一次发送一个文件的时候,盘算出该文件的巨细值,之后每次只需要提取该文件对应的巨细即可。if (fileSize.find(fileName) == fileSize.cend()){fileSize[fileName] = MyGetFileSize(fileName);}LARGE_INTEGER size = fileSize[fileName];///向客户端发送文件巨细长度sprintf_s(cntLen, "Content-length:%lldrn", size.QuadPart);send(sock, cntLen, strlen(cntLen), 0);send(sock, end, strlen(end), 0);wsaBuf.buf = buf;wsaBuf.len = BUF_SIZE;///读取请求文件的数据并通报给客户端do{inFile.read(wsaBuf.buf, BUF_SIZE - 1);int cnt = inFile.gcount();wsaBuf.buf[cnt] = 0;send(sock, buf, cnt, 0);} while (!inFile.eof());inFile.close();//关闭文件return 0;}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364该函数很是重要,注意视察该函数中的回应头信息,头信息必须根据HTTP协议的牢固花样举行发送。

其中又牵扯到了其他几个函数。划分是获取文件的巨细信息ARGE_INTEGER MyGetFileSize(const char * fileName){///建立文件句柄并依此来获取到文件的巨细信息。对于操作系统来讲,每次建立句柄和挪用系统函数将会存在分外的开销,绝对会影响性能HANDLE hFile = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);LARGE_INTEGER size;::GetFileSizeEx(hFile, &size);//获取文件巨细return size;}12345678910获取请求文件的花样char * GetContentType(const std::string& fileName){///通过string的反向查找函数首先查找.符号size_t index = fileName.find_last_of('.');if (index == std::string::npos || index == fileName.size())//请求的文件无后缀名的话 返回一个空指针return nullptr;std::string s(fileName, index + 1);//如果存在后缀的话,那么则检查后缀///通事后缀名来举行判断请求数据的类型std::string type = dataType[s];if (type.empty())return "text/plain";//如果在关联容器中没有找到相对应的类型///返回转换为char*的类型staticchar str[20];strcpy_s(str, type.c_str());return str;}12345678910111213141516171819202122固然其中也牵扯到其他的结构。

这里并纷歧一举例,如果需要请发邮件给我。当你完成基本的结构的时候,则可以测试你的法式。服务器输入 80 端口举行监听。

雷泽体育

此时打开浏览器。输入 localhost并回车此时你的控制台将会打印出毗连的客户信息。固然这是在你实现了该项功效之后。可是最起码你在浏览器中看到你的网页了。

如果你希望能够让其他人也能够看到你网页,你可以实验如下方法:购置服务器并将法式和html文件放在服务器端执行,其他用户通过你的服务器外网IP地址举行会见。2.使用特定的软件举行内网穿透,将内网穿透为公网并设置端口号,其他用户通过你提供的公网IP和端口号举行毗连。

你可以百度“免费frp”来找到心仪的软件,如 Sakura frp如果你不想编写自己的服务器代码,而只想要put自己的网站让其他人会见,你可以使用如下软件:Windows提供的 IIS云盾… 你可以百度搜索网站托管之后如果你想要其他人通过 域名来会见你的网站。如 www.baidu.com就是一个域名。你就需要去购置域名,购置域名士程你可以百度。之后再域名认证存案一系列流程。

存案完成之后将域名与你的服务器公网IP地址举行绑定。如果想要网站响应速度变得更快,那么你可以再设置cdn缓存,同样该步骤可以通过百度查询获得。

如果你域名存案乐成,那么则需要举行剖析。这里给出我的域名剖析方案。

详细你可以百度获得更详细的步骤。当你完成这些之后,那么恭喜你,你的网站应该可以正常被会见了! 那么富厚你的网站让更多人看到吧。


本文关键词:雷泽体育,如,何用,服务器,搭建,自己的,小我,私家,网站

本文来源:雷泽体育-www.hlhbdjc.com