Klasa do obsługi TCP i UDP, opinie i porady

0

Witam, chciałbym zaprezentować klasę którą napisałem do swojego projektu, miała ona maksymalnie ułatwić korzystanie z interfejsu sieciowego. Pomyślałem że ten kawałek kodu może się komuś przydać, a jednocześnie mógłbym z waszą pomocą go udoskonalić. Zaznaczam że jestem w miarę świeżym programistą, więc kod może zawierać trochę(dużo) głupich błędów, coś pewnie można by zrobić lepiej etc.

PS. Klasę oddaje na licencji public domain (ale i tak miło by o mnie wspomnieć w swoim projekcie)

WinSockClass.hpp:

#ifndef WINSOCKCLASS_HPP_INCLUDED
#define WINSOCKCLASS_HPP_INCLUDED
#include <ws2tcpip.h>

#define DEFAULT_BUFLEN 512

class WSA
{
private:
    WSADATA wsaData;
    char *ip;
    int iSendResult;
    int iResult;
    char *port;
    bool UDP;
    sockaddr_in RecvAddr;
    void Initialize();

public:
    int temp;
    int Destiny; // 0 - Client 1-Server
    int error;
    struct addrinfo *result = NULL, *ptr = NULL, hints;
    sockaddr_in SendAddr;
    SOCKET ClientSocket;
    char recvbuf[DEFAULT_BUFLEN];
    WSA(char* IP, int Dest = 0, char* Port = "27015");
    //Client
    void ConnectToSocket(SOCKET Socket, bool UDPConn);
    //Client_End

    //Server
    void Bind(SOCKET Socket, bool UDPConn);
    void Listen(SOCKET Socket, bool UDPConn);
    void AcceptClient(SOCKET Socket, bool UDPConn);
    //Server_End

    //Both
    SOCKET CreateSocket(bool UDPConn);
    void Send(SOCKET Socket, char *sendbuf = "This is test", bool UDPConn = false);
    char* Recv(SOCKET Socket, bool UDPConn);
    void Shutdown(SOCKET Socket);
    //Both_End
};

#endif // WINSOCKCLASS_HPP_INCLUDED

WinSockClass.cpp:

#define _WIN32_WINNT  0x501
#include "WinSockClass.hpp"

#include <iostream>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>

#define DEFAULT_BUFLEN 512
#define SERVER "192.168.100.255"

WSA::WSA(char* IP, int Dest, char* Port)
{
    error = 0;
    //Socket = INVALID_SOCKET;
    ClientSocket = INVALID_SOCKET;
    Destiny = Dest;
    ip = IP;
    port = Port;

    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(atoi(Port));
    RecvAddr.sin_addr.s_addr = INADDR_ANY;

    SendAddr.sin_family = AF_INET;
    SendAddr.sin_port = htons(atoi(Port));
    SendAddr.sin_addr.S_un.S_addr = inet_addr(ip);
    //cout << argv[1] << endl;
    Initialize();
}
void WSA::Initialize()
{
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        error = 1;
        return;
    }
    //CreateSocket();
}
SOCKET WSA::CreateSocket(bool UDPConn)
{
    UDP = UDPConn;

    ZeroMemory( &hints, sizeof(hints) );
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    SOCKET Socket = INVALID_SOCKET;
    if (!UDPConn)
    {
        if (Destiny == 0)
        {
            hints.ai_family = AF_UNSPEC;
            iResult = getaddrinfo(ip, port, &hints, &result);
        }
        else
        {
            hints.ai_family = AF_INET;
            hints.ai_flags = AI_PASSIVE;
            iResult = getaddrinfo(NULL, port, &hints, &result);
        }

        if (iResult != 0) {
            printf("getaddrinfo failed: %d\n", iResult);
            WSACleanup();
            error = 2;
            return Socket;
        }
    }

    // Attempt to connect to the first address returned by
    // the call to getaddrinfo
    if (!UDPConn)
    {
        if(Destiny == 0)
        {
            ptr=result;
            Socket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
        }
        else
        {
            Socket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
        }
    }
    else
    {
        if (Destiny == 0)
        {
            Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
        }
        else
        {
            Socket = socket(AF_INET, SOCK_DGRAM, 0);
        }
    }


    if (Socket == INVALID_SOCKET) {
        std::cout << "Error at socket(): " << WSAGetLastError() << std::endl;
        freeaddrinfo(result);
        WSACleanup();
        error = 3;
        return Socket;
    }
    return Socket;
}
void WSA::ConnectToSocket(SOCKET Socket, bool UDPConn)
{
    // Connect to server.
    iResult = connect( Socket, ptr->ai_addr, (int)ptr->ai_addrlen);
    if (iResult == SOCKET_ERROR) {
        closesocket(Socket);
        Socket = INVALID_SOCKET;
    }

    // Should really try the next address returned by getaddrinfo
    // if the connect call failed
    // But for this simple example we just free the resources
    // returned by getaddrinfo and print an error message

    freeaddrinfo(result);

    if (Socket == INVALID_SOCKET) {
        printf("Unable to connect to server!\n");
        WSACleanup();
        error = 4;
        return;
    }
    return;
}
void WSA::Send(SOCKET Socket, char *sendbuf, bool UDPConn)
{
    // Send an initial buffer
    if(!UDPConn)
    {
        if (Destiny == 0)
        {
            iResult = send(Socket, sendbuf, (int) strlen(sendbuf), 0);
            if (iResult == SOCKET_ERROR) {
                printf("send failed: %d\n", WSAGetLastError());
                closesocket(Socket);
                WSACleanup();
                error = 5;
                return;
            }
        }
        else
        {
            iSendResult = send(ClientSocket, sendbuf, (int) strlen(sendbuf), 0);
            if (iSendResult == SOCKET_ERROR) {
                printf("send failed: %d\n", WSAGetLastError());
                closesocket(ClientSocket);
                WSACleanup();
                error = 10;
                return;
            }
        }
    }
    else
    {
        iResult = sendto(Socket, sendbuf,strlen(sendbuf), 0, (SOCKADDR *) & SendAddr, sizeof(SendAddr));
        if (iResult == SOCKET_ERROR) {
            wprintf(L"sendto failed with error: %d\n", WSAGetLastError());
            closesocket(Socket);
            WSACleanup();
            error = 5;
            return;
        }
    }
    std::cout << "Bytes Sent: " << iResult << std::endl;
    //Recv();
    return;
}
char* WSA::Recv(SOCKET Socket, bool UDPConn)
{
    int SendAddrSize = sizeof (SendAddr);//Only for UDP
    memset(recvbuf, 0, 511);
    do {
            if(!UDPConn)
            {
                if(Destiny == 0)
                {
                    iResult = recv(Socket, recvbuf, DEFAULT_BUFLEN, 0);
                }
                else
                {
                    iResult = recv(ClientSocket, recvbuf, DEFAULT_BUFLEN, 0);
                }
            }
            else
            {
                iResult = recvfrom(Socket, recvbuf, DEFAULT_BUFLEN, 0,(SOCKADDR *) & SendAddr, &SendAddrSize);
            }
        if (iResult > 0)
        {
            temp = iResult;
            printf("Bytes received: %d\n", iResult);
            break;
        }
        else if (iResult == 0)
            printf("Connection closed\n");
        else
            printf("recv failed: %d\n", WSAGetLastError());
    } while (iResult > 0);
    return recvbuf;
}
void WSA::Shutdown(SOCKET Socket)
{
    // shutdown the send half of the connection since no more data will be sent
    if(Destiny == 0)
    {
        iResult = shutdown(Socket, SD_SEND);
    }
    else
    {
        iResult = shutdown(ClientSocket, SD_SEND);
        if(UDP)
            iResult = shutdown(Socket, SD_SEND);
    }

    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed: %d\n", WSAGetLastError());
        closesocket(ClientSocket);
        error = 6;
        return;
    }
    closesocket(Socket);
    closesocket(ClientSocket);
    //WSACleanup();
}
void WSA::Bind(SOCKET Socket, bool UDPConn)
{
    if(!UDPConn)
    {
        iResult = bind(Socket, result->ai_addr, (int)result->ai_addrlen);
    }
    else
    {
        iResult = bind(Socket, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));
    }
    if (iResult == SOCKET_ERROR) {
        printf("bind failed with error: %d\n", WSAGetLastError());
        freeaddrinfo(result);
        closesocket(Socket);
        WSACleanup();
        error = 7;
        return ;
    }
    freeaddrinfo(result);
    return;
}
void WSA::Listen(SOCKET Socket, bool UDPConn)
{
    if ( listen( Socket, SOMAXCONN ) == SOCKET_ERROR ) {
        std::cout << "Listen failed with error: " << WSAGetLastError() << std::endl;
        closesocket(Socket);
        WSACleanup();
        error = 8;
        return;
    }
    return;
}
void WSA::AcceptClient(SOCKET Socket, bool UDPConn)
{
    // Accept a client socket
    ClientSocket = accept(Socket, NULL, NULL);
    if (Socket == INVALID_SOCKET) {
        printf("accept failed: %d\n", WSAGetLastError());
        closesocket(Socket);
        WSACleanup();
        error = 9;
        return;
    }
    return;
}

 
3

Brak konsekwencji w przyjętej konwencji:

  1. nazwy zmiennych: wsaData, ip, iSendResult, iResult, port, UDP, RecvAddr
  2. klamry raz w tej samej linii raz w nowej: if (Socket == INVALID_SOCKET) {, if(!UDPConn)
  3. gwiazdki przy pointerach raz po lewej, raz po prawej
  4. wiadomości raz wyświetlane printf a raz wprintf

Mnóstwo niepotrzebnych return; w funkcjach zwracających void.

Kod w kilku miejscach jest rozjechany, i sugeruje, że jedne instrukcje znajdują się głębiej, niż inne chociaż są w tym samym scopie.

char* Port = "27015" - literal string to const char *, to kompiluje się tylko ze względu na kompatybilność wsteczną z C, próba zmiany stringa wewnątrz wywoła crash programu.

Niektóre komentarze są całkowicie z d**y, i nic nie dają.

memset(recvbuf, 0, 511); - po zmianie #define DEFAULT_BUFLEN 512 recvbuf nie jest całkowicie zerowany.

Użycie bezpośrednie ZeroMemory, WSAStartup, WSACleanup - kod kompatybilny jedynie z Windows. Linux i inne systemy operacyjne całkowicie olałeś.

struct addrinfo *result = NULL, - to nie jest C, że musisz pisać struct przy używaniu struktur.

Jako pole klasy masz: char *port;, natomiast w konstruktorze char* Port, i przypisujesz Port do portu. A co jeśli pamięć pod Port jest zwalniana po wyjściu z konstruktora? (np. tymczasowy obiekt std::string). Nagle wywołując metodę do łączenia mamy pod portem jakieś śmieci. To samo z adresem ip. Dno i wodorosty. Kod idealnie pokazuje jak się nie programuje w c++.

Brak destruktora sprawia, że jeśli się zapomni wywołać Shutdown no to niszcząc obiekt tracimy na zawsze możliwość zamknięcia gniazda. Świetnie.

Nawet nie analizuję poprawności logicznej tego czegoś, bo nie jestem w stanie.

I wiele wiele innych, generalnie kod jest nieczytelny. Nie może być użyty, bo prawdopodobieństwo, że coś w nim jest źle i będzie sypało aplikację w innym miejscu jest niemal pewne.

0

Co powinienem użyć by kod był kompatybilny z innymi systemami ?

0

*klamry raz w tej samej linii raz w nowej: if (Socket == INVALID_SOCKET) {, if(!UDPConn) - poprawione
*gwiazdki przy pointerach raz po lewej, raz po prawej - poprawione
*wiadomości raz wyświetlane printf a raz wprintf - poprawione
*Mnóstwo niepotrzebnych return; w funkcjach zwracających void. - poprawione
char Port = "27015" - literal string to const char *, to kompiluje się tylko ze względu na kompatybilność wsteczną z C, próba zmiany stringa wewnątrz wywoła crash programu. - "poprawione"
*Niektóre komentarze są całkowicie z d**y, i nic nie dają. - wyj***ne :p
*memset(recvbuf, 0, 511); - po zmianie #define DEFAULT_BUFLEN 512 recvbuf nie jest całkowicie zerowany. - poprawione
*struct addrinfo *result = NULL, - to nie jest C, że musisz pisać struct przy używaniu struktur. - poprawione

WinSockClass.hpp:

#ifndef WINSOCKCLASS_HPP_INCLUDED
#define WINSOCKCLASS_HPP_INCLUDED
#include <ws2tcpip.h>

#define DEFAULT_BUFLEN 512

class WSA
{
private:
    WSADATA wsaData;
    char* ip;
    int iResult;
    char* port;
    sockaddr_in RecvAddr;
    void Initialize();

public:
    int Destiny; // 0 - Client 1-Server
    int error;
    addrinfo* result = NULL, *ptr = NULL, hints;
    sockaddr_in SendAddr;
    SOCKET ClientSocket;
    char recvbuf[DEFAULT_BUFLEN];
    WSA(char* IP, int Dest, char* Port);
    //Client
    void ConnectToSocket(SOCKET Socket, bool UDPConn = false);
    //Client_End

    //Server
    void Bind(SOCKET Socket, bool UDPConn = false);
    void Listen(SOCKET Socket);
    void AcceptClient(SOCKET Socket);
    //Server_End

    //Both
    SOCKET CreateSocket(bool UDPConn = false);
    void Send(SOCKET Socket, char* sendbuf = "This is test", bool UDPConn = false);
    char* Recv(SOCKET Socket, bool UDPConn = false);
    void Shutdown(SOCKET Socket);
    //Both_End
};

#endif // WINSOCKCLASS_HPP_INCLUDED
 

WinSockClass.cpp:

#define _WIN32_WINNT  0x501
#include "WinSockClass.hpp"

#include <iostream>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>

#define DEFAULT_BUFLEN 512

WSA::WSA(char* IP, int Dest, char* Port)
{
    error = 0;
    ClientSocket = INVALID_SOCKET;
    Destiny = Dest;
    ip = IP;
    port = Port;

    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(atoi(Port));
    RecvAddr.sin_addr.s_addr = INADDR_ANY;

    SendAddr.sin_family = AF_INET;
    SendAddr.sin_port = htons(atoi(Port));
    SendAddr.sin_addr.S_un.S_addr = inet_addr(ip);

    Initialize();
}
void WSA::Initialize()
{
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != 0)
    {
        std::cerr << "WSAStartup failed: " << iResult << std::endl;
        error = 1;
    }
}
SOCKET WSA::CreateSocket(bool UDPConn)
{
    ZeroMemory( &hints, sizeof(hints) );

    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    SOCKET Socket = INVALID_SOCKET;

    if (!UDPConn)
    {
        if (Destiny == 0)
        {
            hints.ai_family = AF_UNSPEC;
            iResult = getaddrinfo(ip, port, &hints, &result);
        }
        else
        {
            hints.ai_family = AF_INET;
            hints.ai_flags = AI_PASSIVE;
            iResult = getaddrinfo(NULL, port, &hints, &result);
        }

        if (iResult != 0)
        {
            std::cerr << "getaddrinfo failed: " << iResult << std::endl;
            WSACleanup();
            error = 2;
            return Socket;
        }
    }
    if (!UDPConn)
    {
        if(Destiny == 0)
        {
            ptr=result;
            Socket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
        }
        else
        {
            Socket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
        }
    }
    else
    {
        if (Destiny == 0)
        {
            Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
        }
        else
        {
            Socket = socket(AF_INET, SOCK_DGRAM, 0);
        }
    }


    if (Socket == INVALID_SOCKET)
    {
        std::cerr << "Error at socket(): " << WSAGetLastError() << std::endl;
        freeaddrinfo(result);
        WSACleanup();
        error = 3;
    }
    return Socket;
}
void WSA::ConnectToSocket(SOCKET Socket, bool UDPConn)
{
    iResult = connect( Socket, ptr->ai_addr, (int)ptr->ai_addrlen);
    if (iResult == SOCKET_ERROR)
    {
        closesocket(Socket);
        Socket = INVALID_SOCKET;
    }

    freeaddrinfo(result);

    if (Socket == INVALID_SOCKET)
    {
        std::cerr << "Unable to connect to server!" << std::endl;
        WSACleanup();
        error = 4;
    }
}
void WSA::Send(SOCKET Socket, char* sendbuf, bool UDPConn)
{
    if(!UDPConn)
    {
        if (Destiny == 0)
        {
            iResult = send(Socket, sendbuf, (int) strlen(sendbuf), 0);
            if (iResult == SOCKET_ERROR)
            {
                std::cerr << "send failed: " << WSAGetLastError() << std::endl;
                closesocket(Socket);
                WSACleanup();
                error = 5;
                return;
            }
        }
        else
        {
            iResult = send(ClientSocket, sendbuf, (int) strlen(sendbuf), 0);
            if (iResult == SOCKET_ERROR)
            {
                std::cerr << "send failed: " << WSAGetLastError() << std::endl;
                closesocket(ClientSocket);
                WSACleanup();
                error = 10;
                return;
            }
        }
    }
    else
    {
        iResult = sendto(Socket, sendbuf,strlen(sendbuf), 0, (SOCKADDR* ) & SendAddr, sizeof(SendAddr));
        if (iResult == SOCKET_ERROR)
        {
            std::cerr << "sendto failed with error: " << WSAGetLastError() << std::endl;
            closesocket(Socket);
            WSACleanup();
            error = 5;
            return;
        }
    }
    std::cout << "Bytes Sent: " << iResult << std::endl;
}
char* WSA::Recv(SOCKET Socket, bool UDPConn)
{
    int SendAddrSize = sizeof (SendAddr);
    memset(recvbuf, 0, (DEFAULT_BUFLEN-1));
    do {
            if(!UDPConn)
            {
                if(Destiny == 0)
                {
                    iResult = recv(Socket, recvbuf, DEFAULT_BUFLEN, 0);
                }
                else
                {
                    iResult = recv(ClientSocket, recvbuf, DEFAULT_BUFLEN, 0);
                }
            }
            else
            {
                iResult = recvfrom(Socket, recvbuf, DEFAULT_BUFLEN, 0,(SOCKADDR* ) & SendAddr, &SendAddrSize);
            }
        if (iResult > 0)
        {
            std::cout << "Bytes received: " << iResult << std::endl;
            break;
        }
        else if (iResult == 0)
        {
            std::cout << "Connection closed" << std::endl;
        }
        else
        {
            std::cerr << "recv failed: " << WSAGetLastError() << std::endl;
        }
    } while (iResult > 0);
    return recvbuf;
}
void WSA::Shutdown(SOCKET Socket)
{
    shutdown(ClientSocket, SD_SEND);
    shutdown(Socket, SD_SEND);

    closesocket(Socket);
    closesocket(ClientSocket);
}
void WSA::Bind(SOCKET Socket, bool UDPConn)
{
    if(!UDPConn)
    {
        iResult = bind(Socket, result->ai_addr, (int)result->ai_addrlen);
    }
    else
    {
        iResult = bind(Socket, (SOCKADDR* ) & RecvAddr, sizeof (RecvAddr));
    }

    if (iResult == SOCKET_ERROR)
    {
        std::cerr << "bind failed with error: " << WSAGetLastError() << std::endl;
        freeaddrinfo(result);
        closesocket(Socket);
        WSACleanup();
        error = 7;
    }
    freeaddrinfo(result);
}
void WSA::Listen(SOCKET Socket)
{
    if (listen(Socket, SOMAXCONN ) == SOCKET_ERROR )
    {
        std::cerr << "Listen failed with error: " << WSAGetLastError() << std::endl;
        closesocket(Socket);
        WSACleanup();
        error = 8;
    }
}
void WSA::AcceptClient(SOCKET Socket)
{
    ClientSocket = accept(Socket, NULL, NULL);
    if (Socket == INVALID_SOCKET)
    {
        std::cerr << "accept failed: " << WSAGetLastError() << std::endl;
        closesocket(Socket);
        WSACleanup();
        error = 9;
    }
}
 
1

Z poprzedniego posta co nie zostało wykonane:
nazwy zmiennych: wsaData, ip, iSendResult, iResult, port, UDP, RecvAddr

Kod w kilku miejscach jest rozjechany, i sugeruje, że jedne instrukcje znajdują się głębiej, niż inne chociaż są w tym samym scopie.

Użycie bezpośrednie ZeroMemory, WSAStartup, WSACleanup - kod kompatybilny jedynie z Windows. Linux i inne systemy operacyjne całkowicie olałeś.

Jako pole klasy masz: char *port, natomiast w konstruktorze char* Port, i przypisujesz Port do port. A co jeśli pamięć pod Port jest zwalniana po wyjściu z konstruktora? (np. tymczasowy obiekt std::string). Nagle wywołując metodę do łączenia mamy pod portem jakieś śmieci. To samo z adresem ip. Dno i wodorosty. Kod idealnie pokazuje jak się nie programuje w c++.

Brak destruktora sprawia, że jeśli się zapomni wywołać Shutdown no to niszcząc obiekt tracimy na zawsze możliwość zamknięcia gniazda. Świetnie.

// ==

Nowe problemy:

Nadal konstruktor przyjmuje char*, jedynie nie ma domyślnego parametru. Co jeśli sam podam string literal do konstruktora? Dokładnie ten sam problem.
Tak samo tutaj: char* sendbuf = "This is test"

SOCKET CreateSocket(bool UDPConn = false); zwraca SOCKET. Po co?

Pola klasy:

int Destiny; // 0 - Client 1-Server
int error;
addrinfo* result = NULL, *ptr = NULL, hints;
sockaddr_in SendAddr;
SOCKET ClientSocket;
char recvbuf[DEFAULT_BUFLEN];

są ustawione jako public, po co? Żeby z zewnątrz ktoś je mógł zmieniać?

Bezsensowne komentarze nadal nie zniknęły.

Wyświetlanie czegokolwiek przez cout/cerr bez ingerencji z zewnątrz. Po co? Jeśli ktoś nie chce tego mieć to sam sobie ma to usunąć?
Funkcje powinny zwracać bool albo enum z kodami błędów, gdzie jakiś kod to jest sukces, a nie bezmyślne ustawianie jakiegoś errora, który i tak jest z d**y, bo nie jest zerowany. Funkcja jeśli poprawnie się wykona nie ustawia error na 0 i nie wiadomo czy to metoda poprzednia jest sprawczynią błędu czy ta co teraz wywołujemy.

Kody błędów, jeśli już przyjąć, że jakoś je sprawdzamy, nigdzie nie są opisane, i jeśli error będzie ustawiony, to nie wiadomo co on oznacza.
Powinna być funkcja, która z kodu błędu zwróci string, który opisuje ten błąd.

Brak zdefiniowanego konstruktora kopiowania, operatora kopiowania, domyślnego konstruktora, destruktora.
Nie mając operatora kopiowana, kopiując z jednego obiektu do drugiego, pozbawiamy się na zawsze możliwości kontrolowania socketem, więc pozostaje on niezamknięty.

memset(recvbuf, 0, (DEFAULT_BUFLEN-1)); - po co -1 tutaj? Czy to jest c-string, że ostatni znak to jest null terminator czy o co tutaj chodzi?

Nie wiadomo ile bajtów otrzymano z socketu. Pobrałeś tą liczbę, wyświetliłeś ją, ale nigdzie nie została zapisana w taki sposób, aby jakkolwiek można było ją widzieć z zewnątrz.

Już się zorientowałem po co zwracasz SOCKET z tworzenia socketu. Po prostu ty chcesz aby programista korzystający z tego na zewnątrz sobie sam SOCKET trzymał. No bez sensu. Nie wiem o co tutaj chodzi.

Jeśli piszesz w standardzie C++11 (a wierzę, że tak jest, bo starsze standardy to już archaizm, a poza tym używasz inicjalizacji w definicji klasy) to zamiast NULL albo 0 do pointerów używaj nullptr.

Brak komentarzy, które opisują co trzeba podać w parametrach, co zwracają metody, od czego w ogóle jest dana funkcja.

To są jedynie najważniejsze rzeczy, gdyby zebrać całą listę rzeczy, które tutaj są źle, to lista ta byłaby dłuższa niż sam kod.

O samej konstrukcji tego czegoś nawet nie będę się wypowiadał, bo to jest nieużywalne. Korzystanie z gołych funkcji socketa byłoby łatwiejsze.

1 użytkowników online, w tym zalogowanych: 0, gości: 1