Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Winsock - problem z pakietami

Ostatnio zmodyfikowano 2009-05-14 23:05
Autor Wiadomość
jimmye
Temat założony przez niniejszego użytkownika
Winsock - problem z pakietami
» 2009-05-14 10:09:52
Tak więc piszę od kilku dni proxy do gry Endless Online i mam jakiś problem z pakietami, niby program je przesyła (serwer-klient, klient-serwer), ale czasami zmienia sie ich długość, tzn. odbiera pakiet od klienta, który ma 11 bajtów, a wysyła ten sam, tyle, że on ma juz 22 bajty(już jeden pakiet tyle miał) i na końcu jakieś bajty z innego pakietu, przesłanego jako pierwszy.
Oto moja pętla do odbierania/wysyłania pakietów:

C/C++
for(;; )
{
    bytesRecv_c = recv( sClient, recvbuff_c, DEFAULT_BUFFER, 0 );
    if( bytesRecv_c > 0 )
    {
        if( server_work == false )
        {
            client_work = true;
            strRecv_c = recvbuff_c;
            length = strRecv_c.size(); // w trzecim pakiecie jest problem z długością
            output = strRecv_c.substr( 0, bytesRecv_s );
           
            cout << "[RECV C]: " << "[" << pID << "]" << endl;
            strSend = strRecv_c;
            send( sServer, strSend.c_str(), length, 0 );
            client_work = false;
            _sleep( 10 );
        }
    }
    bytesRecv_s = recv( sServer, recvbuff_s, DEFAULT_BUFFER, 0 );
    if( bytesRecv_s > 0 )
    {
        if( client_work == false )
        {
            server_work = true;
            strRecv_s = recvbuff_s;
            length = strRecv_s.size() - 1; // odejmuje 1, bo pakiety odbierane od serwera są wysyłane potem z 1 bajtem więcej
            output = strRecv_s.substr( 0, bytesRecv_s );
           
            cout << "[RECV S]: " << "[" << pID << "]" << endl;
            strSend = strRecv_s;
            send( sClient, strSend.c_str(), length, 0 );
            server_work = false;
            _sleep( 10 );
        }
    }
   
    bytesRecv_c / _s - integer
    recvbuff_c / _s - character[ 1024 ]
P-6809
DejaVu
» 2009-05-14 11:37:22
Niespecjalnie zrozumiałem treść Twojej wypowiedzi (konkretnie opisu problemu). Wiem, że robisz coś z siecią i pakiety, które są wysyłane mają (chyba) 11 bajtów. Ty otrzymujesz w pewnym momencie rozmiar pakietu 22 bajty, który Twoim zdaniem jest nieporządany. Jeśli każdy pakiet ma 11 bajtów, to powinno być oczywiste, że w przypadku 22 bajtów otrzymaleś odrazu dwa pakiety.

Trochę teorii:
1. TCP (sockstream): komunikacja zapewnia dostarczenie pakietu w kolejności w jakiej został wysłany. Protokół ten generuje dodatkowy narzut ruchu sieci, który z punktu widzenia programisty nie ma znaczenia (poza tym, że powinien on sobie zdawać z niego sprawę). Drugą sprawą jest to, iż protokół ten jest wolniejszy. Spowodowane jest to faktem, iż jeśli pakiet nie dojdzie do klienta to zostanie on wysłany ponownie przez serwer bez pisania dodatkowego kodu. Taką funkcjonalność zapewnia protokół TCP.

2. UDP (datagram): umożliwia komunikację bezpołączeniową. Jest to wysyłanie pakietu bez nawiązywania połączenia z serwerem. Klient nie wie czy pakiet dojdzie. Nic nie wiadomo również o tym w jakiej kolejności pakiety dojdą. Zaletą tego protokołu jest generowanie mniejszego ruchu na sieci niż TCP oraz jest znacznie szybszy od protokołu TCP.

Trochę o strumieniu danych:
Największym problemem w pisaniu komunikacji sieciowej jest postać strumienia przychodzących danych. Nie dostajemy w nim informacji w takiej postaci w jakiej wysyłamy, tj. pakiet po pakiecie. W rzeczywistości otrzymujemy ciąg danych binarnych, które zostały już dostarczone do serwera. Przykładowo:
Klient:
wyslij(serwer,'napis1');
wyslij(serwer,'napis2');
wyslij(serwer,'napis3');

Serwer:
czekaj(3000);//czeka 3 sek
odbierz(klient,napis,odebranaDlugosc);

W powyższym przypadku serwer z dużym prawdopodobieństwem otrzyma odrazu napis ze wszystkich 3 pakietów, tj wartość zmiennej napis po stronie serwera będzie następująca:
napis = 'napis1napis2napis3';

Powyższy przykład ilustruje jaki problem sprawia najwięcej trudności przy pisaniu komunikacji sieciowych w grach. Konkretniej: nie jesteśmy w stanie odróżnić na serwerze gdzie się kończy lub zaczyna pakiet. Takie informacje powinny być zawarte w każdym pakiecie, jeśli chcemy mieć różne rozmiary paczek z danymi.
P-6810
jimmye
Temat założony przez niniejszego użytkownika
hmm
» 2009-05-14 11:58:48
Proxy to ma zadanie odbierać pakiety od klienta i dostarczać je do serwera i na odwrót, przy czym moge je edytować "w locie" :P
W grze tej przy łączeniu przechodzą 3 pakiety: 1. żądanie połączenia od klienta, 2. odpowiedź na rządanie, 3. dziwny pakiet(jakiś hash) sprawdza autentyczność serwera.

1-szy pakiet zawsze ma długość 22, drugi trochę inną
3-ci zywkle ma 11 bajtów

Dwa pierwsze pakiety przechodzą bez problemu, prawidłowa długość. Problem polega na tym, że ten trzeci odbierany jest normalnie(11 bajtów), a wysyłany jest o długości 22 bajty, po 11 bajcie reszta informacji, to informacje z pierwszego pakietu, czyli żądanie połączenia.

Dodałem też sobie dodatkowe zmienne: server_work i client_work, które mają zapobiec w pewnym sensie mieszaniu się pakietów, ale w tym przypadku nie skutkuje.
P-6811
DejaVu
» 2009-05-14 23:05:49
Jakoś niejasno problem opisujesz :) Zrozumiałem:
1) odbierasz pakiet 1: 22 bajty
2) odbierasz pakiet 2: ileś bajtów
3) odbierasz pakiet 3: 11 bajtów
4) wysyłasz 3 pakiet o rozmiarze 11 bajtów
5) 'coś' odbiera ten trzeci pakiet, ale ma on 22 bajty
Dobrze zrozumiałem?
P-6851
« 1 »
  Strona 1 z 1