📜 ⬆️ ⬇️

Simple and fast C / C ++ server with C # client: TCP version

Hello. Slowly going through the sheets of books, I do server programming. And my mind got to the point that it would be possible to write on a C ++ server. Well, without thinking twice (or rather without thinking at all, and knowing poorly the advantages), I went to write a server.

And I began to stumble upon different errors, previously alien to me, but incomprehensible to the syntax. And in the end, now I am sharing with you how and how not to write even the simplest server.
So, let's begin.

Let's start with the most important element - the SServer server class:

#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; }; 

Here I think it will not be difficult. We create SOCKET as a socket for the server, it will listen.
WSAData is needed to activate the use of sockets in Windows.
')
That was the headline. Let's go to 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); } } 

And now in order. First, activate WSA by calling WSAStartup (). MAKEWORD sets the version of the libraries that will be connected and the link to the WSAData object. Usually it always works successfully, only you ate not * unix, hehe. Farther. The SOCKADDR_IN structure helps us determine in advance the port and availability of our server. And now I will explain:


Next comes the magic of calling three functions and checking their values ​​on SOCKET_ERROR. I think there is more or less clear. Initialized, zabindili and forced to listen.

SOCK_STREAM talks about using the TCP protocol, SOCK_DGRAM indicates UDP, respectively.
Call the handle of the incoming connections and start checking in an infinite loop.
Create a socket for the incoming connection, structure to fill the address and the length of the structure.
We make a check that our created socket is not connected to the address of such-and-such a computer. And if everything is good, then we display the message and connect from the address of our client and create a client who will later process everything himself.

Now the client code. Header and implementation together:

 #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); } } 

Here, too, as you can see, there is nothing complicated. the main thing is the handle () function, which we immediately launch in the constructor. The recv () function is preferably used with TCP, and recvfrom () with the UDP protocol, respectively.

And lastly. In main.cpp It looks like this:

 #include "SServer.h" int main() { SServer server ; server.port = 3487;//  ushort -   cin.get()  ..    .    server.startServer(); return 0; } 

And the file you so often saw includes.h. Here he is:

 #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; 

Bottom line: We learned how to create a simple TCP server in C ++ by reading a good article in Habré
The UDP version will be the same, but the differences are very small and I think soon there will be too.

Also everything is on GitHub

Source: https://habr.com/ru/post/327574/


All Articles