Клиент создает одно соединение, но принимается три

 
0
 
C++
ava
Aoizora | 11.12.2016, 13:56
Пишу программу для удаленного администрирования по сети. Сервер запускается на моем компьютере, который находится за НАТом, клиент может быть где угодно. Для подключения к себе использую Dynamic DNS. Проброс портов настроил так: (роутер D-Link DIR-620, админка с темным дизайном)

[img]http://s015.radikal.ru/i333/1612/4d/e8edd8c48703.png[/img]

Мой сервер работает на порту 666, к нему делается проброс через порт 55000 из внешней сети.

Исходники клиента и сервера:

Сервер:

#include <WinSock2.h>
#include <Ws2tcpip.h>
#include <Windows.h>
#include <stdio.h>
#include <stdint.h>

#pragma comment(lib, "ws2_32.lib")

#define LOCAL_PORT 666
#define DEFAULT_PORT "666"    /* Must be the same as PORT */
#define MAX_CONNECTIONS 10

BOOL WINAPI InitWinSock();
void WINAPI FormatError(DWORD error);
SOCKET WINAPI BindSocket(uint16_t port);
DWORD WINAPI HandleConnection(LPVOID sock);
void WINAPI PrintClientInfo(sockaddr_in *addr);

int main(int argc, char *argv[])
{
    SOCKET server;
    SOCKET client;
    DWORD ThreadID;
    sockaddr_in client_addr;
    int addr_len = sizeof(client_addr);

    if (InitWinSock())
    {
        server = BindSocket(LOCAL_PORT);
        if (listen(server, MAX_CONNECTIONS) == SOCKET_ERROR)
        {
            FormatError(WSAGetLastError());
            WSACleanup();
            return -1;
        }

        printf("Acception loop\n");
        while (TRUE)
        {
            client = accept(server, (struct sockaddr *)&client_addr, &addr_len);
            printf("Accepted!\n");
            if (client != INVALID_SOCKET)
            {
                PrintClientInfo(&client_addr);
                CreateThread(NULL, 0, HandleConnection, &client, NULL, &ThreadID);
            }
        }
        WSACleanup();
    }
}

BOOL WINAPI InitWinSock()
{
    WSADATA wsadata;
    if (FAILED(WSAStartup(MAKEWORD(2, 2), &wsadata)))
    {
        FormatError(WSAGetLastError());
        return FALSE;
    }
    return TRUE;
}

void WINAPI FormatError(DWORD errCode)
{
    char error[1000]; 
    FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
        NULL,
        WSAGetLastError(),
        MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
        error, sizeof(error), NULL);
    printf("\nError: %s\n", error);
}

SOCKET WINAPI BindSocket(uint16_t port)
{
    SOCKET sock = INVALID_SOCKET;
    sockaddr_in local_addr;

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == INVALID_SOCKET)
    {
        FormatError(WSAGetLastError());
    }
    else
    {
        RtlZeroMemory(&local_addr, sizeof(local_addr));
        local_addr.sin_family = AF_INET;
        local_addr.sin_port = htons(port);
        local_addr.sin_addr.s_addr = INADDR_ANY;

        if (bind(sock, (struct sockaddr *)&local_addr, sizeof(local_addr)) == SOCKET_ERROR)
        {
            FormatError(WSAGetLastError());
        }
        else
        {
            printf("Server running on port %u address %s...\n", local_addr.sin_port, inet_ntoa(local_addr.sin_addr));
        }
    }

    return sock;
}

DWORD WINAPI HandleConnection(LPVOID sock)
{
    SOCKET client;
    HANDLE hFile = NULL;
    char buffer[200];
    int recv_bytes = 0;
    DWORD bytes_written = 0;

    printf("Handle connection...\n");

    client = *(SOCKET *)sock;
    
    char msg[] = "hello";
    send(client, msg, sizeof(msg), 0);

    shutdown(client, SD_BOTH);
    closesocket(client);

    printf("Connection closed\n");

    return 0;
}

void WINAPI PrintClientInfo(sockaddr_in *addr)
{
    char hostname[NI_MAXHOST];

    getnameinfo((struct sockaddr *)addr, sizeof(*addr), hostname, sizeof(hostname), NULL, 0, 0);
    printf("+ %s [%s] new connection\n", hostname, inet_ntoa(addr->sin_addr));
}



Клиент:

#include <Ws2tcpip.h>
#include <stdio.h>
#include <stdint.h>
#include "auth.h"
#include "error.h"

#pragma comment(lib, "ws2_32.lib")

#define LOCAL_PORT 667
#define REMOTE_HOST "z0r.ddns.net"
#define REMOTE_PORT 55000
#define DEFAULT_PORT "55000"    /* Must be the same as REMOTE_PORT */
#define MAX_CONNECTIONS 10

SOCKET WINAPI BindSocket(uint16_t port);
DWORD WINAPI HandleConnection(LPVOID sock);
void WINAPI BackConnect(char *hostname);

int main(int argc, char *argv[])
{
    WSADATA wsadata;
    SOCKET server;
    SOCKET client;
    DWORD ThreadID;
    sockaddr_in client_addr;
    int addr_len = sizeof(client_addr);

    if (FAILED(WSAStartup(MAKEWORD(2, 0), &wsadata)))
    {
        FormatError(WSAGetLastError());
    }
    else
    {
        server = BindSocket(LOCAL_PORT);
        if (listen(server, MAX_CONNECTIONS) == SOCKET_ERROR)
        {
            FormatError(WSAGetLastError());
            WSACleanup();
            return -1;
        }

        printf("Listening port %d...\n", LOCAL_PORT);

        BackConnect(REMOTE_HOST);
        while (TRUE)
        {
            client = accept(server, (struct sockaddr *)&client_addr, &addr_len);
            if (client != INVALID_SOCKET)
            {
                CreateThread(NULL, 0, HandleConnection, &client, NULL, &ThreadID);
            }
        }
        WSACleanup();
    }
}

SOCKET WINAPI BindSocket(uint16_t port)
{
    SOCKET sock = INVALID_SOCKET;
    sockaddr_in local_addr;

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == INVALID_SOCKET)
    {
        FormatError(WSAGetLastError());
    }
    else
    {
        RtlZeroMemory(&local_addr, sizeof(local_addr));
        local_addr.sin_family = AF_INET;
        local_addr.sin_port = htons(port);
        local_addr.sin_addr.s_addr = INADDR_ANY;

        if (bind(sock, (struct sockaddr *)&local_addr, sizeof(local_addr)) == SOCKET_ERROR)
        {
            FormatError(WSAGetLastError());
        }
        else
        {
            printf("Server running...\n");
        }
    }

    return sock;
}

BOOL MyCmp(char *s1, char *s2)
{
    for (int i = 0; *s1 && *s2; s1++, s2++)
        if (*s1 != *s2)
            return FALSE;
    return TRUE;
}

DWORD WINAPI HandleConnection(LPVOID sock)
{
    SOCKET client = INVALID_SOCKET;
    HANDLE hFile = NULL;
    char buffer[200];
    DWORD bytes_written = 0;
    int auth_flag = 0;

    client = *(SOCKET *)sock;

    SendData(client, "command>");

    while (TRUE)
    {
        ZeroMemory(buffer, sizeof(buffer));
        int recv_bytes = recv(client, buffer, sizeof(buffer), 0);
        if (recv_bytes > 0)
        {
            if (MyCmp(buffer, "exit"))
            {
                printf("command: exit\n");
                break;
            }
            else if (MyCmp(buffer, "help"))
            {
                printf("command: help\n");
                SendData(client, "\thello\r\n");
            }
            else if (MyCmp(buffer, "auth"))
            {
                auth_flag = AuthProc(client);
            }
        }
        else break;

        SendData(client, "command>");
    }

    closesocket(client);
    printf("Connection closed\n");

    return 0;
}

void WINAPI BackConnect(char *hostname)
{
    struct addrinfo *result = NULL;
    struct addrinfo *ptr = NULL;
    struct addrinfo hints;
    struct sockaddr_in *remote_addr_ptr = NULL;
    SOCKET sock = INVALID_SOCKET;

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

    getaddrinfo(hostname, DEFAULT_PORT, &hints, &result);
    ptr = result;

    if (ptr->ai_family == AF_INET)
    {
        remote_addr_ptr = (struct sockaddr_in *)ptr->ai_addr;
        printf("IPv4 address %s, port %u\n", inet_ntoa(remote_addr_ptr->sin_addr), remote_addr_ptr->sin_port);

        sock = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
        if (sock == INVALID_SOCKET)
        {
            FormatError(WSAGetLastError());
        }
        else
        {
            //remote_addr_ptr->sin_addr.s_addr = inet_addr("127.0.0.1");
            remote_addr_ptr->sin_port = htons(REMOTE_PORT);
            if (connect(sock, (struct sockaddr *)remote_addr_ptr, sizeof(*remote_addr_ptr)) == SOCKET_ERROR)
            {
                printf("Connection to %s port %u failed\n", inet_ntoa(remote_addr_ptr->sin_addr), remote_addr_ptr->sin_port);
                FormatError(WSAGetLastError());
            }
            else
            {
                char szComputerName[MAX_PATH];
                DWORD dwSize = MAX_PATH / sizeof(TCHAR);

                GetComputerNameA(szComputerName, &dwSize);
                SendData(sock, szComputerName);
            }
            closesocket(sock);
        }
    }
}


Проблема возникает при соединении клиента с сервером. Сейчас и клиент и сервер находятся на моем компютере несмотря на то, что соединение происходит через Dynamic DNS. Вот скрины:

Это на сервере
[img]http://s013.radikal.ru/i323/1612/bd/2f5dd8bf2fa1.png[/img]

Это на клиенте

[img]http://s018.radikal.ru/i519/1612/eb/26677ed7136d.png[/img]

Почему на сервере появляется три сообщения о подключении, если клиент создает только одно? Почему на клиенте функция connect завершается с ошибкой, а WSAGetLastError говорит, что операция завершена успешно?
Kommentare (1)
ava
feodorv | 11.12.2016, 21:17 #
Это точно клиент??? Зачем ему listen()???
Цитата (Aoizora @  11.12.2016,  13:56 findReferencedText)
if (listen(server, MAX_CONNECTIONS) == SOCKET_ERROR)
    {
    FormatError(WSAGetLastError());
    WSACleanup();
    return -1;
    }



Цитата (Aoizora @  11.12.2016,  13:56 findReferencedText)
Почему на сервере появляется три сообщения о подключении, если клиент создает только одно? Почему на клиенте функция connect завершается с ошибкой, а WSAGetLastError говорит, что операция завершена успешно?

Ох. Ну Вы же точно можете отлокализовать вывод сообщений об ошибках. И, определив место, догадаться, что к чему. Например:

if (bind(sock, (struct sockaddr *)&local_addr, sizeof(local_addr)) == SOCKET_ERROR)
        {
            printf( "Error source: file = %s, line = %d\n", __FILE__, __LINE__);
            FormatError(WSAGetLastError());
        }
Или:

void WINAPI FormatError(DWORD errCode, const char *fileName, int lineNumber)
{
    char error[1000]; 
    FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
        NULL,
        WSAGetLastError(),
        MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
        error, sizeof(error), NULL);
    printf("\nError: %s\n(file = %s, line = %d)\n", error, fileName, lineNumber);
}
Registrieren Sie sich oder melden Sie sich an, um schreiben zu können.
Unternehmen des Tages
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Mitwirkende
advanced
Absenden