Winsock получает случайные буквы через recv () - PullRequest
0 голосов
/ 18 октября 2019

Я пытаюсь сделать чат Winsock. Я хочу отправить пакеты, которые сидят между 2 "тегами". вроде как "^^^ TAG ^^^ пакет данных ^^^ TAG ^^^"

Проблема в том, что используемые мной клиентские приложения, включая мое собственное клиентское приложение, которое я написаллибо отправьте сообщение неверно, либо мое серверное приложение получит данные неправильно

Вот что я имею в виду:

Использование клиента Hercules TCP

Используя мой собственный клиент

Я знаю, почему он разделен, для этого и нужна идея моего тега, но если вы прочитаете то, что я отправляю, и то, что я получил, вы увидите добавленные и замененные буквы. В какой-то момент я даже получил слова, которые я отправил, а затем "================================" другиеслучайные символы Юникода, но я не смог получить его снова на скриншот.

Из-за того, что большинство клиентов TCP, которых я отключил от интернета, не работало, я предполагаю, что проблема в том, как я получаюпакеты, а не то, как я и другие программы отправляют их

Мой код:

Вот переписанная простая версия моего кода

struct client_info
{
    SOCKET sock;
    const char* ip;
    int port;
};

struct server_info
{
    SOCKET sock;
    const char* ip;
    int port;
    std::vector<client_info> clients;
    int client_count;

    HANDLE connection_handler;
    HANDLE recv_handler;
};

struct param_info
{
    void* server_info_pointer;
};

class my_server
{
public:
    my_server(const char* ip, int port)
    {
        this->m_info.ip = ip;
        this->m_info.port = port;

        this->start();
        this->client_handler();
        this->recv_packet();
    }
    ~my_server(void)
    {

    }
private:
    server_info m_info;

    bool start(void)
    {
        WSADATA lpWsaData = decltype(lpWsaData){};

        WSAStartup(MAKEWORD(2, 2), &lpWsaData);
        this->m_info.sock = socket(AF_INET, SOCK_STREAM, 0);

        sockaddr_in lpAddr = decltype(lpAddr){};
        lpAddr.sin_family = AF_INET;
        lpAddr.sin_addr.S_un.S_addr = inet_addr(this->m_info.ip);
        lpAddr.sin_port = htons(this->m_info.port);

        char chOption = 1;
        setsockopt(this->m_info.sock, SOL_SOCKET, SO_REUSEADDR, &chOption, sizeof(chOption));
        setsockopt(this->m_info.sock, IPPROTO_TCP, TCP_NODELAY, &chOption, sizeof(chOption));

        if (!bind(this->m_info.sock, reinterpret_cast<sockaddr*>(&lpAddr), sizeof(lpAddr)))
        {
            return true;
        }

        closesocket(this->m_info.sock);
        WSACleanup();
        return false;
    }

    bool client_handler(void)
    {
        param_info pi = param_info{};
        pi.server_info_pointer = &this->m_info;

        if (this->m_info.connection_handler = CreateThread(nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>
            (this->client_handler_internal), &pi, 0, nullptr))
        {
            return true;
        }

        return false;
    }

    static void client_handler_internal(void* param)
    {
        auto pi = reinterpret_cast<param_info*>(param);

        if (!listen(reinterpret_cast<server_info*>(pi->server_info_pointer)->sock, SOMAXCONN))
        {
            client_info ci = client_info{};

            sockaddr_in lpAddr;
            int dAddrSize = sizeof(lpAddr);

            while (ci.sock = accept(reinterpret_cast<server_info*>(pi->server_info_pointer)->sock, reinterpret_cast<sockaddr*>(&lpAddr), &dAddrSize))
            {
                ci.ip = inet_ntoa(lpAddr.sin_addr);
                ci.port = htons(lpAddr.sin_port);

                printf("%s:%d joined!\n", ci.ip, ci.port);

                reinterpret_cast<server_info*>(pi->server_info_pointer)->clients.push_back(ci);

                memset(&ci, 0, sizeof(ci));
                Sleep(100);
            }
        }

        return;
    }

    auto __forceinline recv_packet(void) -> bool
    {
        param_info pi = param_info{};
        pi.server_info_pointer = &this->m_info;

        if (this->m_info.recv_handler = CreateThread(nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>
            (this->recv_packet_internal), &pi, 0, nullptr))
        {
            return true;
        }

        return false;
    }

    static void recv_packet_internal(void* param)
    {
        auto pi = reinterpret_cast<param_info*>(param);

        for (;;)
        {
            for (int i = 0; i < reinterpret_cast<server_info*>(pi->server_info_pointer)->clients.size(); ++i)
            {
                char * lpBuffer = new char[64];
                if (0 < recv(reinterpret_cast<server_info*>(pi->server_info_pointer)->clients.at(i).sock, lpBuffer, sizeof(lpBuffer), 0))
                {
                    std::string lpNewBuffer = lpBuffer;
                    printf("%s\n", lpNewBuffer.c_str());
                }

                memset(lpBuffer, 0, sizeof(lpBuffer));
            }

            Sleep(50);
        }

        return;
    }
};

1 Ответ

4 голосов
/ 18 октября 2019
if (0 < recv(reinterpret_cast<server_info*>(pi->server_info_pointer)->clients.at(i).sock, lpBuffer, sizeof(lpBuffer), 0))

Вы игнорируете возвращаемое значение recv, поэтому ваш код не знает, сколько байт он получил. Также см. Ниже, почему sizeof(lpBuffer) здесь не так.

memset(lpBuffer, 0, sizeof(lpBuffer));

Поскольку lpBuffer - это char *, это обнуляет sizeof(char *) байт, что неправильно. Используйте sizeof только тогда, когда вам нужен размер типа . Кроме того, почему вы обнуляете буфер, который вы уже использовали и никогда не будете использовать снова?

std::string lpNewBuffer = lpBuffer;

Вы должны были использовать возвращаемое значение из recv, чтобы узнать, сколько байтов lpNewBuffer должно быть.

Не рассматривайте вещи как строки, если они не являются строками. Сохраните возвращаемое значение recv, чтобы вы знали, сколько байт вы получили.

...