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

[WinAPI-Winsock] Synchronizacja pętli wysyłającej i odbierającej.

Ostatnio zmodyfikowano 2013-12-29 20:32
Autor Wiadomość
Vister26
Temat założony przez niniejszego użytkownika
[WinAPI-Winsock] Synchronizacja pętli wysyłającej i odbierającej.
» 2013-12-28 22:49:18
Oto uproszczony kod serwera:
C/C++
POINT pt;
pt.x = 0; pt.y = 0;

for(;; ) {
    pt.x++; pt.y++
    itoa( pt.x, sendbuf, 10 );
    send( masterSocket, sendbuf, strlen( sendbuf ), 0 );
    itoa( pt.y, sendbuf, 10 );
    //tutaj dodalem sleep
    send( masterSocket, sendbuf, strlen( sendbuf ), 0 );
}
oraz uproszczony kod klienta:
C/C++
POINT pt;

//tutaj dodalem sleep
for(;; ) {
    memset( recvbuf, 0, 32 * sizeof( char ) );
    recv( masterSocket, recvbuf, 32, 0 );
    pt.x = atoi( recvbuf );
    memset( recvbuf, 0, 32 * sizeof( char ) );
    recv( masterSocket, recvbuf, 32, 0 );
    pt.y = atoi( recvbuf );
   
    cout << recvbuf << endl
    << "pt.x = " << pt.x << endl
    << "pt.y = " << pt.y << endl;
}

Niby wszystko działa poprawnie, z małym mankamentem - co jakiś czas wartość x lub y na milisekundy zmienia wartość na niepoprawną (np. zamieniają się ze sobą wartościami albo stają się potwornie duże). Myślę, że może to być spowodowane tym, że pętla serwera działa szybciej od pętli klienta(ew. odwrotnie), mam rację? Jak to naprawić?

@Edit:
Udało mi się to względnie dobrze poprawić, dodałem Sleep() tak, żeby serwer wysyłał dane co ok. 0.1 sekundy, a w kliencie dodałem Sleep(50) przed pętlą for. Niestety, działa to tylko wtedy kiedy klient i serwer są włączone na moim komputerze, natomiast jeśli ja włączam serwer a kolega klienta na innym kompie - znowu są błędy
P-100439
Admixior
» 2013-12-29 03:58:08
Przed chwilą w innym poście napisałem:
Musisz uważać na TCP/IP gdyż to strumień i albo (jak napisał kolega wyżej) korzystać z gotowych paczek, albo samemu zaimplementować pseudo-paczkę wysyłając rozmiar, gdyż TCP/IP to strumieniowa transmisja, czyli możesz nie odróżnić końca poprzedniej paczki od początku następnej. W przypadku niewielkiej ilości danych nie ma problemu, ale jak zaczniesz wysyłać setki kilobajtów to może się okazać że twój program się pogubi. Nikt nie daje gwarancji że to co wyślesz dojdzie OD RAZU w całości. Zawsze dojdzie i będzie odpowiednia koleność, ale może się okazać że najpierw dojdzie "CLO" a później "SE", a nie od razu "CLOSE".

Tutaj (obstawiam) jest dokładnie taki problem. Ping powoduje że nie działa tak samo na jednym kompie jak na różnych. Więc kontroluj wartość zwracaną przez recv (ilość odebranych bajtów). Najlepiej napisz sobie funkcje która odbierze określoną ilość, i nic więcej nic mniej i sprawdzi ewentualnie błędy. W tym celu posłuż się dokumentacją i zabawą ze wskaźnikami i adresowaniem.

recv(...) - dokumentacja msdn

PS. nie musisz konwertować danych na tekst. Dane binarne tak samo się wysyła i odbiera.

int a=5;
send(socket, &a, sizeof(a), 0);

recv(socket, &a, sizeof(a), 0);


Po za tym zauważyłem że popełniasz inny błąd:
Wysyłasz `strlen(...)` znaków czyli tyle ile jest konieczne a odbierasz zawsze 32, przez co odbierasz znaki aktualne jak i następne (tak żeby w sumie cyfr wyszło 32). Przez to wychodzą ci ogromne liczby. I jeszcze musisz uważać żeby po odebraniu danych jako tekst, a właściwie przed traktowaniem ich jako tekst upewnić się że jest na końcu null - najlepiej samemu go dodać. W tym przypadku zerujesz 32 elementową tablicę i później pobierasz 32 elementy więc miejsca na nulla nie ma.
P-100456
Vister26
Temat założony przez niniejszego użytkownika
» 2013-12-29 20:32:53
Dzięki za wyczerpującą odpowiedź, dużo mi pomogłeś.

@Edit:

Ulepszyłem trochę generator pt.x i pt.y(tak, żeby generował tylko liczby z przedziału od 1 do 9999), napisałem funckje wysyłającą, która wysyła pt.x i pt.y w postaci: CCCCi gdzie 'C' to cyfra(jako char, nie int) lub NULL, natomiast 'i' to indeks - x lub y. Funkcja odbierająca w nieskończonej pętli odbiera pierwsze 5 znaków, które do niej trafią, sprawdza czy 5 znak to indeks x lub y - jeśli tak to przypisuje do odpowiednich wartości pt.x lub pt.y, jeśli nie to sprawdza jeszcze raz. U kolegi działa bezbłędnie z opóźnieniem wysyłania 100ms(na mniejszych jeszcze nie sprawdzaliśmy). U mnie bez żadnych ograniczeń.

W kodzie wygląda to tak:
C/C++
for(;; ) {
    memset( recvbuf, 0, 8 * sizeof( char ) ); // 8 na wszelki wypadek
    recv( masterSocket, recvbuf, 5, 0 );
    if( recvbuf[ 4 ] == 'x' ) { pt.x = atoi( recvbuf ); } //klamry na wszelki wypadek
    else if( recvbuf[ 4 ] == 'y' ) { pt.y = atoi( recvbuf ); }
   
    system( "cls" );
    cout << recvbuf << endl;
    cout << "pt.x = " << pt.x << endl;
    cout << "pt.y = " << pt.y << endl;
}
P-100576
« 1 »
  Strona 1 z 1