Проблема в приеме соединения от клиента (программирование сокетов) в Visual C ++ - PullRequest
0 голосов
/ 24 октября 2010

Я написал простое однопоточное клиент-серверное приложение на Visual C ++ . Когда я запускаю свой сервер, я некоторое время жду, пока он примет какой-то запрос от клиента.

Когда я подключаю клиента к серверу. Сообщение журнала на клиенте сообщает, что отправлено 14 байтов, а на сервере нет сообщения. Я написал оператор печати для печати всего, что принято сервером, на консоли, но сервер ничего не печатает.

Мне кажется, что клиент подключился к другому серверу.

Код клиента и сервера указан ниже.

Код сервера

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <conio.h>

#define DEFAULT_PORT        "27015"
#define DEFAULT_BUFLEN        512
#pragma comment(lib, "Ws2_32.lib")

int main() {
    WSADATA wsdata;
    int result = WSAStartup(MAKEWORD(2,2),&wsdata);
    if (result != 0){
        printf("%s","Unable to initilize windows socket\n");
        getch();
        return 1;
    }

    struct addrinfo *addrResult = NULL,hints;
    ZeroMemory(&hints, sizeof (hints));

    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    result = getaddrinfo(NULL,DEFAULT_PORT,&hints,&addrResult);
    if (result != 0){
        printf("%s","Error in getaddrInfo");
        getch();
        return 1;
    }
    SOCKET listenSocket = INVALID_SOCKET;
    listenSocket = socket(addrResult->ai_family,addrResult->ai_socktype,addrResult->ai_protocol);

    if (listenSocket == INVALID_SOCKET){
        printf("%s","Error in creating socket object\n");
        getch();
        closesocket(listenSocket);
        WSACleanup();
        return 1;
    }

    sockaddr_in service;
    service.sin_family = AF_INET;
    service.sin_addr.s_addr = inet_addr("127.0.0.1");
    service.sin_port = htons(27015);

    if (bind(listenSocket,addrResult->ai_addr,
        (int)addrResult->ai_addrlen) == SOCKET_ERROR){
    //if(bind(listenSocket,(SOCKADDR*) &service,
    //    sizeof(service)) == SOCKET_ERROR){

        printf("bind failed: %d\n", WSAGetLastError());
        freeaddrinfo(addrResult);
        closesocket(listenSocket);
        WSACleanup();
        getch();
        return 1;
    }
    freeaddrinfo(addrResult);
    if (listen(listenSocket,SOMAXCONN) == SOCKET_ERROR){
        printf("%s","Error in listening socket");
        getch();
        closesocket(listenSocket);
        WSACleanup();
    }
    SOCKET clientSocket = INVALID_SOCKET;
    clientSocket = accept((listenSocket,NULL,NULL);
    if (clientSocket ==  INVALID_SOCKET){
        closesocket(listenSocket);
        WSACleanup();
    }

    char recvbuf[DEFAULT_BUFLEN];
    int iRecvResult, iSendResult;
    int recvbuflen = DEFAULT_BUFLEN;

    do{
        iRecvResult = 0;
        iSendResult = 0;
        iRecvResult = recv(clientSocket,recvbuf,recvbuflen,0);
        if (iRecvResult > 0){
            printf("Bytes received: %d\n", iRecvResult);
            getch();
            // Echo the buffer back to the sender
            iSendResult = send(clientSocket, recvbuf, iRecvResult, 0);
            if (iSendResult == SOCKET_ERROR) {
                printf("send failed: %d\n", WSAGetLastError());
                closesocket(clientSocket);
                WSACleanup();
                return 1;
            }
            printf("Bytes sent: %d\n", iSendResult);
        }
        else if (iRecvResult == 0){
            printf("Connection closing...\n");
        }
        else{
            printf("recv failed: %d\n", WSAGetLastError());
            closesocket(clientSocket);
            WSACleanup();
            return 1;
        }
    }while(iRecvResult > 0);
  getch();
  return 0;
}

Код клиента

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <conio.h>

#define DEFAULT_PORT        "27015"
#define DEFAULT_BUFLEN        512
#pragma comment(lib, "Ws2_32.lib")

int main(){
    WSADATA wsdata;
    WSAStartup(MAKEWORD(2,2),&wsdata);
    struct addrinfo *addrResult = NULL,hints;
    ZeroMemory(&hints, sizeof (hints));
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_family = AF_UNSPEC;
    int result = 0;
    if (getaddrinfo("127.0.0.1",DEFAULT_PORT,
        &hints,&addrResult)){
            printf("%s","Error in getaddrInfo\n");
            WSACleanup();
            getch();
            return 1;
    }
    SOCKET connectingSocket = INVALID_SOCKET;
    connectingSocket = socket(addrResult->ai_family,addrResult->ai_socktype,
        addrResult->ai_protocol);
    if (connectingSocket == INVALID_SOCKET){
        printf("%s","Error in creating socket\n");
        freeaddrinfo(addrResult);
        WSACleanup();
        getch();
        return 1;
    }

    if (connect(connectingSocket,addrResult->ai_addr, (int)addrResult->ai_addrlen) != 0){
        closesocket(connectingSocket);
        connectingSocket = INVALID_SOCKET;
        WSACleanup();

    }
    freeaddrinfo(addrResult);

    int recvbuflen = DEFAULT_BUFLEN;
    char *sendbuf = "this is a test";
    char recvbuf[DEFAULT_BUFLEN];

    int iResult;

    // Send an initial buffer
    iResult = send(connectingSocket, sendbuf, (int) strlen(sendbuf), 0);
    if (iResult == SOCKET_ERROR) {
        printf("send failed: %d\n", WSAGetLastError());
        closesocket(connectingSocket);
        WSACleanup();
        return 1;
    }

    printf("Bytes Sent: %ld\n", iResult);

    // shutdown the connection for sending since no more data will be sent
    // the client can still use the connectingSocket for receiving data
    iResult = shutdown(connectingSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed: %d\n", WSAGetLastError());
        closesocket(connectingSocket);
        WSACleanup();
        return 1;
    }

    // Receive data until the server closes the connection
    do {
        iResult = recv(connectingSocket, recvbuf, recvbuflen, 0);
        if (iResult > 0)
            printf("Bytes received: %d\n", iResult);
        else if (iResult == 0)
            printf("Connection closed\n");
        else
            printf("recv failed: %d\n", WSAGetLastError());
    } while (iResult > 0);

    getch();
    return 0;
}

Ответы [ 4 ]

1 голос
/ 24 октября 2010

Хмм ... после исправления очевидной синтаксической ошибки (несоответствующие открытые скобки в clientSocket = accept((listenSocket,NULL,NULL);), это, кажется, работает достаточно хорошо для меня.На сервере я получаю:

Получено байт: 14
Отправлено байт: 14
Закрытие соединения ...

и на клиенте:

Отправлено байт: 14
Получено байт: 14
Ошибка recv: 10054

Итак, клиент отправляет 14 байтов на сервер (вы нажимаете ввод)сервер передает эти 14 байтов обратно клиенту (вы снова нажимаете ввод), и сервер закрывает соединение.Клиент читает 14 байтов, затем дальнейшее чтение завершается неудачно, когда соединение закрывается.

Редактировать: я запустил код, открыв два окна командной строки Windows SDK, запустив server в одном и client вдругие - ничего особенно интересного или необычного ни в одном из них.

1 голос
/ 24 октября 2010

Вы можете подтвердить, что происходит в коде вашего сервера, когда клиент пытается отправить, улучшив диагностику. Увеличение выходных данных в важные моменты (например, успешное выполнение connect(), accept(), close(), ВСЕ ошибки сокетов, возможно, дополнительный файл журнала трафика send/recv), вероятно, быстро укажет путь к решению. Убедитесь, что вы проверяете и выводите любые ошибки при ВСЕХ вызовах API сокетов.

Вы можете проверить, прослушивают ли другие системы ваш целевой порт / адрес, используя netstat.

Я не вижу ничего очевидного неправильно.

0 голосов
/ 27 ноября 2010

В клиенте вы закрываете соединение для отправки:

// shutdown the connection for sending since no more data will be sent
// the client can still use the connectingSocket for receiving data
iResult = shutdown(connectingSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
    printf("shutdown failed: %d\n", WSAGetLastError());
    closesocket(connectingSocket);
    WSACleanup();
    return 1;
}

Сервер обнаруживает отключение (recv return 0) и завершает работу, не закрывая соединение на своей стороне, поэтому вы получаете сообщение об ошибке 100054.

0 голосов
/ 28 октября 2010

Я бы посоветовал вам сделать следующее:

  • Удалить все getch () из кода ради эксперимента
  • Убедитесь, что ниваш tcp-сервер и приложения tcp-клиента не работают
  • Удалите все правила для ваших приложений в настройках брандмауэра Windows
  • запустите следующее в оболочке CMD - вам нужно сделать доступным GREP:

    netstat -a -b |grep -e "27015" --after = 1

Если выходные данные этой команды не пусты - вы увидите имя приложения, которое является источником проблемы.В противном случае попробуйте воспроизвести проблему, запустив сервер, а затем - клиента.Контролируйте состояние сервера с помощью команды netstat, как указано выше (или с помощью программы tcpview).Интересно, каковы будут результаты.

Примечание в автономном режиме: Ваша последовательность отсоединения неполная.Google для graceful disconnect.Обычно это выглядит так:

[ client ] испускают shutdown (sd_send) и ждут оставшиеся данные с сервера

[ server ] если recv () == 0, то { send (оставшиеся данные);испустить shutdown (sd_send); closesocket }

[ клиент ] получать оставшиеся данные;если recv () == 0, то closesocket

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...