MyHttp、ソケット[0]から始まるサーバーとHttpリクエストクラスを実装します



Myhttp Implement Server



まず、同様の文字列が必要です

私は実際にはC ++が好きではありません。書くのは精神的に負担が大きすぎるだけでなく、非常に粗雑です。 c ++ 20がまもなく発売されると聞きました。私はc ++ 11さえ知りませんが、17は言うまでもなく、C ++入門書はほぼ2000ページであると推定しています。標準ライブラリにはまだネットワークライブラリがないと推定されています。ライブラリ管理ツールがなければ、私は常にc#とNugetが好きです。
stlの文字列は単純すぎて、c#の記述に慣れていると、単純に使用できないように感じますが、パフォーマンスは悪くありません。他のプロジェクト、oopパッケージング、確実な開閉の原則に簡単に移行するには、文字列を継承してMyStringを実装するのが最善の選択であり、後でいつでも変更できます。

プロジェクトコードウェアハウス GitHub



class MyString:public string { public: MyString()=default ~MyString()=default template<class T> MyString(T&& arg) :string(forward<T>(arg)) { } vector<MyString> Split(MyString flag,bool SkipEmpty=true) { vector<MyString> return_data int pos = find(flag) bool FirstLine = true while (pos!=-1) { MyString line auto PushData=[&return_data,SkipEmpty](MyString line){ if (line.length() != 0 || !SkipEmpty) { return_data.push_back(line) } } if (FirstLine) { line = substr(0, pos) PushData(line) FirstLine = false } else { int right = find(flag, pos+1) int left = pos + flag.length() if (right==-1) { line = substr(left) PushData(line) break } line = substr(left, right - left) PushData(line) pos = right } } return return_data } vector<MyString> Split(char flag=' ') { vector<MyString> return_data istringstream data data.str(data()) string temp while (getline(data,temp,flag)) { return_data.push_back(temp) } return return_data } MyString Trim(char target=' ') { int left=find_first_not_of(target) int right = find_last_not_of(target) return substr(left, right-left+1) } private: }

ソケットとhttpとは何ですか?これは他の人に直接依存します。
まず、httpはtcpに基づいています
写真は他の人からのもので、侵入されて削除されました
画像

ソケットを使用して、Httpリクエストデータを通過させる必要があります

ソケットを取得する

SOCKET GetSocket(int port, bool IsServer = false) { //initialization. ,WSA windows asynchronous socket WSADATA inet_WsaData// WSAStartup(MAKEWORD(2, 0), &inet_WsaData)//socket2.0 version if (LOBYTE(inet_WsaData.wVersion) != 2 || HIBYTE(inet_WsaData.wVersion) != 0) {//The high byte indicates the minor version, and the low byte indicates the major version WSACleanup() return -1 } auto tcp_socket = socket(AF_INET,SOCK_STREAM, 0)//ipv4, tcp, tcp or udp this parameter can be 0 if (!IsServer) { return tcp_socket }//The server needs to do the following sockaddr_in saddr saddr.sin_family = AF_INET//ipv4 udp tcp etc. saddr.sin_port = htons(port) //port saddr.sin_addr.s_addr = INADDR_ANY//Is the listening address if (::bind(tcp_socket, (sockaddr*)&saddr, sizeof(saddr)) == -1) {//Because of using namespace std, you should use :: to specify global functions instead of std::bind throw exception('bind error') } if (::listen(tcp_socket, 20) == -1)//The socket handle of the monitor, which specifies the maximum number of connections to monitor {//The listen function turns the socket into a passive type, waiting for the client's connection request. throw exception('listen error') } return tcp_socket }

Connectを使用して接続する

in_addr sa MyString ServerAddr = '127.0.0.1'//I opened the .net core web server to test locally, you can replace it yourself if (InetPton(AF_INET,ServerAddr.c_str(),&sa)==-1) { throw new exception('Address conversion error') } sockaddr_in saddr saddr.sin_family = AF_INET//ipv4 saddr.sin_port = htons(5000)//port saddr.sin_addr=sa if (::connect(Socket, (sockaddr*)&saddr, sizeof(saddr))!=0) { MyString Msg = 'Connection failed error code:' + WSAGetLastError() throw new exception(Msg.c_str()) }

sendを使用してリクエストを送信します

MyHttp::Request a//myhttp is placed at the bottom a.SetHttpMethod(MyHttp::MethodEnum::Get) a.Path = '/api/auth/zanllp' a.Header['Host'] = '127.0.0.1:5000' a.Header['Accept-Encoding']='gzip, deflate, br' a.Header['Accept'] = 'text/html,application/xhtml+xml,application/xmlq=0.9,image/webp,image/apng,*/*q=0.8' a.Header['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0 WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 OPR/58.0.3135.79' MyString SendBuf = a.SendRequest() cout << SendBuf << endl send(Socket, SendBuf.c_str(), SendBuf.length(), 0)

recvを使用して応答を読み取ります

char buf[1024] = { '' } recv(Socket, buf, sizeof(buf), 0)//1 MyHttp::Response da(buf) cout << da.ParseFromSource()<< endl

結果

画像
基本的に簡単なリクエストができます

IPをどうしたらいいのかわからない?

MyString GetIpByHostname(MyString hostname) { addrinfo hints, *res in_addr addr int err memset(&hints, 0, sizeof(addrinfo)) hints.ai_socktype = SOCK_STREAM hints.ai_family = AF_INET//ipv4 if ((err = getaddrinfo(hostname.c_str(), NULL, &hints, &res)) != 0) { MyString Msg = 'error' + err + MyString(gai_strerror(err)) throw exception(Msg.c_str()) } addr.s_addr = ((sockaddr_in*)(res->ai_addr))->sin_addr.s_addr char str[INET_ADDRSTRLEN] auto ptr = inet_ntop(AF_INET, &addr, str, sizeof(str)) freeaddrinfo(res) return str } //Modify as follows in connetcion MyString ServerAddr = MyHttp::GetIpByHostname('www.baidu.com') if (InetPton(AF_INET,ServerAddr.c_str(),&sa)==-1) { throw new exception('Address conversion error') } sockaddr_in saddr saddr.sin_family = AF_INET saddr.sin_port = htons(80) saddr.sin_addr=sa

急げ

現在のMyHttpの進捗状況

#include #include #include #include #include #include #include #include #include #include #include namespace MyHttp { MyString GetIpByHostname(MyString hostname) { addrinfo hints, *res in_addr addr int err memset(&hints, 0, sizeof(addrinfo)) hints.ai_socktype = SOCK_STREAM hints.ai_family = AF_INET//ipv4 if ((err = getaddrinfo(hostname.c_str(), NULL, &hints, &res)) != 0) { MyString Msg = 'error' + err + MyString(gai_strerror(err)) throw exception(Msg.c_str()) } addr.s_addr = ((sockaddr_in*)(res->ai_addr))->sin_addr.s_addr char str[INET_ADDRSTRLEN] auto ptr = inet_ntop(AF_INET, &addr, str, sizeof(str)) freeaddrinfo(res) return str } enum MethodEnum { Get, Post, Put, Delete } class Response { public: MyString Source MyString ProtocolVersion = 'HTTP/1.1' MyString Code = '200' MyString Status = 'ok' MyString Server = 'CppTinyServer' map<MyString, MyString> Header MyString ResponseBody ~Response() = default Response() = default template<class T> Response(T&& arg) { Source = MyString(forward<T>(arg)) } MyString& BuildResponseHeader() { Source = ProtocolVersion + ' ' + Code + ' ' + Status + ' ' Header['Server'] = Server Header['Content-Length'] = to_string(ResponseBody.length()) for (auto x : Header) { Source += x.first + ':' + x.second + ' ' } Source += ' ' return Source } MyString& ParseFromSource() { auto ThrowError = [] {throw exception('Parse error') } auto data = Source.Split(' ') if (data.size()==0) { return ResponseBody } auto FirstLine = data[0].Split(' ') if (FirstLine.size() != 3) { ThrowError() } // ProtocolVersion = FirstLine[0].Trim() Code = FirstLine[1].Trim() Status = FirstLine[2].Trim() data.erase(data.begin()) // for (auto x : data) { auto pair = x.Split(':') if (pair.size() != 2) { continue } Header[pair[0].Trim()] = pair[1].Trim() } // if (Source.find(' ')==Source.length()+4) { return ResponseBody } ResponseBody = move(*--data.end()) return ResponseBody } } class Request { public: MyString Source MyString Method MyString Path MyString ProtocolVersion = 'HTTP/1.1' map<MyString, MyString> Header MyString RequestBody Request() = default ~Request() = default template<class T> Request(T&& arg) { Source = MyString(forward<T>(arg)) } void SetHttpMethod(MethodEnum method, MyString other = '') { if (other != '') { Method = other return } switch (method) { case MethodEnum::Get: Method = 'GET' break case MethodEnum::Post: Method = 'POST' break case MethodEnum::Put: Method = 'PUT' break case MethodEnum::Delete: Method = 'DELETE' break default: break } } void ParseFromSource() { auto ThrowError = [] {throw exception('Parse error') } if (Source.length() < 10) { ThrowError() } auto data = Source.Split(' ') if (data.size() == 0) { ThrowError() } //Request line auto FirstLine = data[0].Split(' ') if (FirstLine.size() != 3) { ThrowError() } Method = FirstLine[0].Trim() Path = FirstLine[1].Trim() ProtocolVersion = FirstLine[2].Trim() data.erase(data.begin()) //Request header for (auto x : data) { auto pair = x.Split(':') if (pair.size() != 2) { if (pair.size() == 3)//host:127.0.0.1:5000 { Header[pair[0].Trim()] = pair[1].Trim() + ':' + pair[2].Trim() } continue } Header[pair[0].Trim()] = pair[1].Trim() } //Request body if (Source.find_last_of(' ') == Source.length() + 2) { return } RequestBody =move( *--data.end()) } MyString SendRequest() { Source = Method + ' ' + Path + ' ' + ProtocolVersion + ' ' for (auto x : Header) { Source += x.first + ':' + x.second + ' ' } Source += ' ' Source += RequestBody return Source } } }

プロジェクトをGitHubにプッシュする時間が数日あるのを待つのは少し面倒です。サーバーも実行できますが、スレッドプールの代わりにスレッドを使用します。理解してから書きます。このシリーズには12を超える記事がある場合もあれば、単純な場合もあります。 C#は依然として世界最高であり、await + async + taskには、wpfのクロススレッド更新インターフェイス、またはTMがタスクを処理するインターフェイスに直接プルすることを除いて、解決できないマルチスレッド非同期タスクはありません。お絵かき。それはまだ立ち往生していますが、欠陥はほとんど隠れていません。重要なことは私のために十分なお金を稼ぐことです。

大物は星を与える GitHub