winsock не удается подключиться к локальному хосту

#c #winapi #winsock

#c #winapi #winsock

Вопрос:

Для моего проекта я не могу отладить программу, поэтому я не могу быть уверен, почему возникает эта ошибка.

Моему серверу, размещенному на c #, не удается подключиться к серверу на локальном хосте.

Вместо того, чтобы отправлять обратно сигнал «connection» на мой сервер, он никогда не подключается, я думаю, что код написан хорошо, и я не вижу никаких ошибок, возможно, я где-то допустил неосторожную ошибку

Кроме того, Я ДОЛЖЕН использовать gethostbyname вместо getaddrinfo

пространство имен winsock:

 SOCKET WinSock::ConnectToServer(PCHAR IP, USHORT Port)
{
    WSADATA WSA;
    if (WSAStartup(MAKEWORD(2, 0), amp;WSA))
    {
        SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (s != SOCKET_ERROR)
        {
            hostent *Host = gethostbyname(IP);
            if (Host != ERROR)
            {
                SOCKADDR_IN Addr;

                Addr.sin_family = AF_INET;
                Addr.sin_port = htons(Port);
                Addr.sin_addr.s_addr = NULL;

                if (bind(s, PSOCKADDR(amp;Addr), sizeof(Addr)) > 0)
                {
                    return s;
                }
            }
        }
    }

    return FALSE;
}

BOOL WinSock::SendData(SOCKET s, PBYTE Packet)
{
    DWORD PacketSize = lstrlenA(PCHAR(Packet));
    if (send(s, PCHAR(amp;PacketSize), 8, 0) > NULL)
    {
        if (send(s, PCHAR(Packet), PacketSize, 0) > NULL)
        {
            return TRUE;
        }
    }
    return FALSE;
}
 

основной метод:

 int main()
{
    char key = 1;
    SOCKET S = WinSock::ConnectToServer(0, 55480);
    while(true)
    {
        WinSock:SendData(S, (PBYTE)key);
    }
}
 

Комментарии:

1. Вы не видите никаких ошибок, потому что нет абсолютно никакого кода, проверяющего ошибки и сообщающего об этом. Но send возвращает ssize_t , поэтому вам не следует сравнивать это с NULL . И bind возвращает 0 либо отрицательное число, либо положительное целое число. Поэтому сравнение > 0 бесполезно.

2. @Cheatah я отключил crt, поэтому я даже не могу проверить наличие ошибок, я должен их знать.

3. @Cheatah итак, с чем я должен сравнить bind вместо этого? == 0/ERROR_SUCCESS?

4. опубликованный код использует несколько конструкций кода C (которые не могут быть скомпилированы на C). Пожалуйста, удалите c тег

5. функция: send() возвращает a ssize_t , а не указатель, например NULL`

Ответ №1:

             if (bind(s, PSOCKADDR(amp;Addr), sizeof(Addr)) > 0)
 

Описание этого кода заключается в том, что он должен подключаться к серверу. Но проблема в том, что bind() не подключается ни к одному серверу. Он только связывает сокет с локальным портом. Это то, что делают серверы, которые прослушивают сокеты. Предположительно, это тот же порт, который уже открыт сервером, следовательно bind() , сбой. Если сервер не прослушивал bind() , по иронии судьбы, это удастся. Но в любом случае это не будет подключаться ни к чему.

Вы хотите использовать connect() и нет bind() .

Кроме того, я должен отметить, что если эта функция сначала создает сокет, но затем не может установить соединение по этой или любой другой причине, она вернет сообщение об ошибке, но не сможет закрыть сокет, что приведет к утечке дескриптора сокета. Вы также должны исправить эту ошибку.

Ответ №2:

На самом деле вы не устанавливаете соединение с сервером. Вы вызываете bind() , чтобы привязать клиентский сокет к локальному порту 55480, но это не создает соединение. Вместо этого вам нужно вызвать connect() , чтобы подключить клиентский сокет к удаленному порту 55480.

Кроме того, ваш SendData() код неверен. Он указывает send() отправить 8 байт для PacketSize , но размер a DWORD составляет всего 4 байта. И send() не возвращается NULL при сбое. И send() не гарантируется отправка всех запрошенных байтов, поэтому вам нужно вызывать его в цикле. И принято отправлять многобайтовые целые числа в сетевом байтовом порядке (big endian).

Кроме того, вы запрограммировали SendData() ожидание строки в стиле C с нулевым завершением, но это не то, что вы main() на самом деле передаете ему.

Попробуйте что-то вроде этого:

 bool WinSock::Init()
{
    WSADATA WSA;
    return (WSAStartup(MAKEWORD(2, 0), amp;WSA) == 0);
}

bool WinSock::Cleanup()
{
    return (WSACleanup() == 0);
}

SOCKET WinSock::ConnectToServer(const char *IP, unsigned short Port)
{
    hostent *Host = gethostbyname(IP);
    if ((Host != NULL) amp;amp; (Host->h_addrtype == AF_INET)
    {
        SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (s != INVALID_SOCKET)
        {
            SOCKADDR_IN Addr = {};

            Addr.sin_family = AF_INET;
            Addr.sin_port = htons(Port);
            Addr.sin_addr.s_addr = * (u_long*) Host->h_addr;

            if (connect(s, PSOCKADDR(amp;Addr), sizeof(Addr)) != SOCKET_ERROR)
            {
                return s;
            }

            closesocket(s);
        }
    }

    return INVALID_SOCKET;
}

bool WinSock::Close(SOCKET s)
{
    return (closesocket(s) == 0);
}

bool WinSock::SendData(SOCKET s, const void* Data, DWORD DataSize)
{
    const char *ptr = (const char*) Data;

    while (DataSize > 0)
    {
        int numSent = send(s, ptr, DataSize, 0);
        if (numSent == SOCKET_ERROR) return false;
        ptr  = numSent;
        DataSize -= numSent;
    }

    return true;
}

bool WinSock::SendData(SOCKET s, const char *Packet)
{
    DWORD PacketSize = lstrlenA(Packet);
    DWORD tmp = htonl(PacketSize);
    if (!SendData(s, amp;tmp, sizeof(tmp)) return false;
    return SendData(s, Packet, PacketSize);
}
 
 int main()
{
    if (WinSock::Init())
    {
        const char *key = "1";
        SOCKET S = WinSock::ConnectToServer(NULL, 55480);
        if (s != INVALID_SOCKET)
        {
            while (true)
            {
                WinSock:SendData(S, key);
            }
            WinSock::Close(s);
        }
        WinSock::Cleanup();
    }

    return 0;
}