Re[2]: Сервер виснет после первого соединения
От: Alex_v99 Россия  
Дата: 23.03.09 13:48
Оценка:
TarasCo:

TC>Это в общем случае UB, надо closesocket делать


Простите, но что есть "UB" и где взять функцию closesocket? В каталоге <include/*.h> её нету, и компилятор её не знает.

--------------------------------------------------------
andreytsb:

A>В идеальных условиях (на локальной машине) даже при одновременном подключении нескольких клиентов (с помощью telnet) сервер обработал всех поочередно: как только отсоединялся текущий — обрабатывалось следующее соединение).

A>Проблема очень интересная. Чтобы полностью разобратся нужно лицезреть полный код клиента и сервера.

Вот код сервера, собран с помощью GNU GCC под Debian Etch4:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream>

int main()
{
    int sock, listener;
    struct sockaddr_in addr;
    char buf[1024];
    int bytes_read;

    listener = socket(AF_INET, SOCK_STREAM, 0);
    if (listener < 0)
    {
        return 1;
    }

    addr.sin_family = AF_INET;
    addr.sin_port = htons(3425);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(listener, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        return 2;
    }
    while (1)
    {
        listen(listener, 1);

        while(1)
        {
            sock = accept(listener, NULL, NULL);
            if (sock < 0)
            {
                return 3;
            }

            while(1)
            {
                bytes_read = recv(sock, buf, 1024, 0);

                if (bytes_read <= 0) break;
                    send(sock, buf, bytes_read, 0);

                std::cout << buf << std::endl;
            }

            close(sock);
        }
    }

    return 0;
}


Клиент, который собственно не работает. Собран под MSVC6.0 + MFC в виде простейшего диалога с кнопкой. Код выполняется по нажатию на эту кнопку. Первое нажатие отрабатывает как положено, сервер всё принимает/отсылает/печатает, второе и последующие нажатия — никакой реакции сервера. В отладчике видно, что pUM_Socket->Connect() возвращает 0.

void CUmEmulatorDlg::OnButtonConnect() 
{
    if (pUM_Socket) // переменная объявлена как CSocket* CUmEmulatorDlg::pUM_Socket;
    {
        AfxMessageBox("Already connected!");
        return;
    }

    pUM_Socket = new CSocket();
    CString Str;
    Str = "192.168.0.22";
    int nPort = 3425;

    pUM_Socket->Create(nPort, SOCK_STREAM, NULL);
    pUM_Socket->Connect(Str, nPort);

    Str = "SESSION BEGIN AB5643F8865CD0\n";
    pUM_Socket->Send(Str.GetBuffer(Str.GetLength()), Str.GetLength(), 0);
    pUM_Socket->Receive(Str.GetBuffer(Str.GetLength()), Str.GetLength(), 0);

    Str = "GET STATE AB5643F8865CD0\n";
    pUM_Socket->Send(Str.GetBuffer(Str.GetLength()), Str.GetLength(), 0);
    pUM_Socket->Receive(Str.GetBuffer(Str.GetLength()), Str.GetLength(), 0);

    pUM_Socket->Close();
    
    delete pUM_Socket;
    pUM_Socket = NULL;
}


Для проверки написал простенький аналог этого клиента под Debian, но запустить его, к сожалению, могу лишь локально с сервером, а по реальной сети запускать его не на чем. Этот клиент работает корректно, сколько бы раз его ни запускали, при том, что он сам по себе делает пяток независимых соединений:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream>

char message[] = "Hello there!\n";
char buf[sizeof(message)];

int main()
{
    int sock;
    struct sockaddr_in addr;

    for (int i=0; i<5; i++)
    {    sock = socket(AF_INET, SOCK_STREAM, 0);
        if(sock < 0)
        {
          return 1;
        }

        addr.sin_family = AF_INET;
        addr.sin_port = htons(3425);
        addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
        if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
        {
         return 2;
        }

        send(sock, message, sizeof(message), 0);
        recv(sock, buf, sizeof(message), 0);

        std::cout << buf << std::endl;
        close(sock);
    }
    return 0;
}


======================================================
Пока писал этот текст, провёл несложный эксперимент:
Запустил сервер. Подключился удалённым клиентом несколько раз. Как и раньше, получилось лишь единожды. После этого, не выключая сервер, запустил локальный клиент и сервер корректно обработал его запросы.

Очевидно, что либо клиент под MFC работает некорректно, либо сервер как-то иначе обрабатывает именно loopback-соединения (вообще-то он и знать об этом не должен, но мало ли...).

Может у кого-нибудь есть мысли, где тут собака порылась?..
WBR, Alex.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.