そして、私はさまざまなエラーに出くわし始めましたが、それは以前は私には異質でしたが、構文は理解できませんでした。 そして最後に、最も簡単なサーバーであっても、どのように書くべきか、どのように書かないべきかを共有します。
さあ、行きます。
最も重要な要素であるSServerサーバークラスから始めましょう。
#pragma once #include "includes.h" class SServer { public: SServer(); ~SServer(); void startServer(); void closeServer(); void handle(); unsigned short port; private: SOCKET this_s; WSAData wData; };
ここでは難しいことではないと思います。 SOCKETをサーバーのソケットとして作成します。サーバーはリッスンします。
WSADataは、Windowsでソケットの使用をアクティブにするために必要です。
それが見出しでした。 CPPに進みましょう。
#include "SServer.h" #include "includes.h" SServer::SServer(){ } SServer::~SServer(){ } void SServer::startServer(){ if (WSAStartup(MAKEWORD(2, 2), &wData) == 0) { printf("WSA Startup succes\n"); } SOCKADDR_IN addr; int addrl = sizeof(addr); addr.sin_addr.S_un.S_addr = INADDR_ANY; addr.sin_port = htons(port); addr.sin_family = AF_INET; this_s = socket(AF_INET, SOCK_STREAM, NULL); if (this_s == SOCKET_ERROR) { printf("Socket not created\n"); } if (bind(this_s, (struct sockaddr*)&addr, sizeof(addr)) != SOCKET_ERROR) { printf("Socket succed binded\n"); } if (listen(this_s, SOMAXCONN) != SOCKET_ERROR){ printf("Start listenin at port%u\n", ntohs(addr.sin_port)); } handle(); } void SServer::closeServer() { closesocket(this_s); WSACleanup(); cout << "Server was stoped. You can close app" << endl; } void SServer::handle() { while (true) { SOCKET acceptS; SOCKADDR_IN addr_c; int addrlen = sizeof(addr_c); if ((acceptS = accept(this_s, (struct sockaddr*)&addr_c, &addrlen)) != 0) { printf("send\n"); printf("sended Client connected from 0 %u.%u.%u.%u:%u\n", (unsigned char)addr_c.sin_addr.S_un.S_un_b.s_b1, (unsigned char)addr_c.sin_addr.S_un.S_un_b.s_b2, (unsigned char)addr_c.sin_addr.S_un.S_un_b.s_b3, (unsigned char)addr_c.sin_addr.S_un.S_un_b.s_b4, ntohs(addr_c.sin_port)); SClient* client = new SClient(acceptS, addr_c); } Sleep(50); } }
そして今、順番に。 まず、WSAStartup()を呼び出してWSAをアクティブにします。 MAKEWORDは、接続するライブラリのバージョンとWSADataオブジェクトへの参照を設定します。 通常、Unixがない場合にのみ、常に正常に動作します。 さらに。 SOCKADDR_IN構造は、サーバーのポートと可用性を事前に決定するのに役立ちます。 そして今、私は説明します:
- INETADDR_ANYは、任意のユーザーマシンからサーバーにアクセスできることを示します。 inet_aadr( "127.0.0.1")の記述方法を指定すると、ローカルネットワークでテストすることさえできなくなります。
- htons()は、ushortの使用中にハードウェアをネットワークショートに変換する関数です。 次はntohs()関数です-それは逆に機能します
- AF_INET-デバイスがIPv4、AF_INET6-IPv6を介してグローバルネットワークを使用するという事実に責任を持つ定数
次に、3つの関数
SOCK_STREAMは、それぞれTCPプロトコルSOCK_DGRAM-UDPの使用について説明します。
着信接続ハンドル()のハンドラーを呼び出し、無限ループでチェックを開始します。
着信接続用のソケット、アドレスを入力する構造、および構造の長さを作成します。
作成したソケットが、コンピューターからのそのようなアドレスに接続されていないことを確認します。 そして、すべてが順調であれば、メッセージを表示し、クライアントのアドレスから接続し、将来すべてを処理するクライアントを作成します。
クライアントコード。 見出しと実装を一緒に:
#pragma once #include "includes.h" class SClient { public: SClient(SOCKET s, SOCKADDR_IN sock_in); ~SClient(); void handle(); private: SOCKET c_sock; SOCKADDR_IN c_addr; char buffer[1024]; }; SClient::SClient(SOCKET s, SOCKADDR_IN sock_in) { c_sock = s; c_addr = sock_in; printf("Client created\n"); handle(); } SClient::~SClient() { } void SClient::handle() { while (true) { int k = recv(c_sock, buffer, sizeof(buffer), NULL); if(k>0){ printf(buffer); } Sleep(30); } }
ここでも、ご覧のとおり、複雑なことは何もありません。 主なものは、コンストラクタですぐに実行するhandle()関数です。 recv()関数は、それぞれTCPで、recvfrom()はUDPプロトコルで使用するのが望ましいです。
そして最後に。 main.cppでは、次のようになります。
#include "SServer.h" int main() { SServer server ; server.port = 3487;// ushort - cin.get() .. . server.startServer(); return 0; }
そして、あなたがよく見たファイルには、.hが含まれます。 ここに彼は:
#pragma once #pragma comment(lib, "ws2_32.lib") #pragma warning(disable: 4996) #include <iostream> #include <WinSock2.h> #include <winsock.h> #include "SClient.h" using namespace std;
結論:Habrに関する良い記事を読んだ後、C ++で簡単なTCPサーバーを作成する方法を学びました
UDPバージョンもありますが、違いは非常に小さく、すぐにここに来ると思います。
すべてがGitHubにあります