Obsługa WinSocket, działa ale jest mały problem

0

Witam
Otóż na bazie różnych źródeł w internecie, napisałem program, który łączy się z jakimś serwerem i wyświetla nam odpowiedź. Programik jest konsolowy, ale ogólnie działa, jeśli połączy się z serwerem to wyświetli ramkę zwrotną (nagłówek + plik np index.html).

Problem polega na tym, iż podczas gdy funkcje z biblioteki WinSocket łączą się z serwerem, program się zamraża na chwilę, w ogóle nie odpowiada. Jak np nie ma w sieci urządzenia o podanym adresie IP to program potrafi się zamrozić na ok 20 sekund. Gdy urządzenie jest, podczas odpytywania, program się zamraża na ćwierć lub pół sekundy (tak na oko ;P ), chociaż zdarzały się sytuację, iż program się zamrażał nawet na 2, 3 sekundy, mimo iż urządzenie było w sieci (brak problemów sprzętowych).
Sęk w tym, że jak będę potrzebował odpytywać układ np co 3 sekundy, to to może być dość uciążliwe (tutaj jest tylko program łączący się z serwerem raz, w innym programie wywołuję funkcję "main" ok. raz na 3 sek). Czy jest jakiś sposób, a w zasadzie inna metoda, by uniknąć takich zgrzytów? A może akurat wykorzystywany przeze mnie sposób jest jednym z najgorszych jakie mogłem znaleźć w sieci?

Z góry dziękuję za wszelką pomoc :)

PS: gdy będę chciał przenieść program do wersji okienkowej (korzystając z WinForms + MVS C++ 2005), to chyba implementowanie tego nie będzie najlepszym pomysłem, i wydaje mi się że WinForms mają już wbudowane coś tego typu? Oczywiście nie chodzi mi o to, by forumowicze od razu mi podali cały kod na tacy, ale wystarczy słowo klucz, z jakich funkcji, bibliotek czy coś w tym stylu skorzystać pisząc program w WinForms. Później mogę sobie sam poszukać :)

Tutaj jest kod źródłowy jakby ktoś chciał zobaczyć:
(Jakby ktoś chciał sprawdzić, to musi do zmiennej hostname wpisać jakiś adres ip (sam adres ip), 192.168.1.1 niekoniecznie musi działać u każdego :] )

#include <iostream>
#include <string>
#include <stdlib.h>
#include <assert.h>
#include <Winsock2.h>

#define SEND_RQ(MSG) send(sock,MSG,strlen(MSG),0);
using namespace std;

int Result(int result);

int main()
{
    int iResult;
    string message;
    char *hostname = "192.168.1.1";

	WSADATA	WsaData;
	WSAStartup (0x0101, &WsaData);

    sockaddr_in sin;
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    
    if (sock == -1)
        Result( -100);
	
    sin.sin_family = AF_INET;
    sin.sin_port = htons( (unsigned short)80);
    struct hostent * host_addr = gethostbyname(hostname);
    
    if(host_addr==NULL)
    {
        cout<<"Unable to locate host"<<endl;
        Result( -103);
    }
    
    sin.sin_addr.s_addr = *((int*)*host_addr->h_addr_list);
    cout<<"Port :"<<sin.sin_port<<", Address : "<< sin.sin_addr.s_addr<<endl;

    if( connect (sock,(const struct sockaddr *)&sin, sizeof(sockaddr_in) ) == -1 )
    {
        cout<<"connect failed"<<endl;
        Result( -101);
    }

    SEND_RQ("POST /test.html HTTP/1.0\n\rHost:");
    SEND_RQ(hostname);  //192.168.1.1
    SEND_RQ("\n\rUser-Agent: Mozilla/4.0\n\r\n\r");


    char c1[1];
    int l,line_length;
    bool loop = true;
    bool bHeader = false;

    while(loop)
    {
        l = recv(sock, c1, 1, 0);
        if(l<0)
            loop = false;
        if(c1[0]=='\n')
        {
            if(line_length == 0)
                loop = false;
            line_length = 0;
            if(message.find("200") != string::npos)      //lub samo "200"
                bHeader = true;
        }
        else if(c1[0]!='\r')
            line_length++;
        cout<<c1[0];
        message += c1[0];
    }

    message="";
 
    if(bHeader)
    {
        char p[1024];
        while((l = recv(sock,p,1023,0)) > 0)
        {
            cout.write(p,l) ;
            p[l] = '\0';
            message += p;
        }
    }
    else
        Result( -102);

    WSACleanup( );
    printf("\t\n%s\n", message.c_str());  //zawartość pobranego pliku
    system("pause");
    return 0;
}

//=================================
//      Result
//=================================
int Result(int result)
{
    printf("%d\n", result);    
    system("pause");
    exit(result);
}


0

Może po prostu połączenia niech się odbywają w wątkach. Wtedy problem zamrażania ustanie. Aplikacje konsolowe są wykonywane 'linijka po linijce' dlatego też program oczekuje na wykonanie jednej funkcji, aby przejść do kolejnej.

0

No chyba w przypadku aplikacji konsolowych (w [natywnym?] "zwykłym" C++) najlepiej byłoby to wrzucić w nowy wątek. ( dla szukających, tutaj coś o tworzeniu wątków: http://cpp0x.pl/kursy/Kurs-WinAPI-C++/Zaawansowane/Watki/337 ).

Natomiast w przypadku pisania później w środowisku .NET (np w C++ z dodatkowym wykorzystaniem WinForms), środowisko dostarcza odpowiednich narzędzi:

  • System::Threading
  • System::Net

Chociaż może w środowisku .NET obsługa socketów jest tak zrobiona, że nie trzeba by było tego dodatkowo wpakowywać w nowe wątki? Potestuje, to zobaczymy :]

1 użytkowników online, w tym zalogowanych: 0, gości: 1