Autor Wątek: [C] winsock - pakiety nie docierają  (Przeczytany 1936 razy)

Offline Jaklub

  • Użytkownik

# Marzec 02, 2010, 22:57:32
tym razem nie będę was zasypywał dziesiątkami linijek mojego kodu. nie chcę zamiast pomocy dostawać linka do artykułu "Jak nie lamić" z waszego wiki. poza tym, nie wiem, jaki mam dać tytuł temu tematowi.
na początku multiplayera do mojej gry próbowałem zaprogramować przy użyciu 39dll (biblioteka stworzona pod niesławnego tutaj GMa). wszystko działało przepięknie, bez żadnych bugów, poza jednym - po około 180 tysiącach poleceń z dlla gra po prostu się wyłączała (prawdopodobnie coś nie tak z wczytaniem tych funkcji). bez żadnego błędu, ot tak. postanowiłem więc przenieść grę na Winsocka - i tu zaczęły pojawiać się kolejne problemy. większość jakoś rozwiązywałem, ale nie mam pomysłu, co zrobić z tymi opisanymi niżej. wczoraj zaobserwowałem, że pakiety od serwera nie dochodzą do klientów kiedy nie są wysyłane w pętli while. kiedy nowy klient właśnie został zaakceptowany (i tuż po tym wysyłany jest pakiet), wiadomości czasami docierają, czasami nie - z tym niby sobie poradziłem przez opóźnienie przesyłania nowych wiadomości, ale stwierdziłem, że coś może być nie tak i gdybym chciał przetestować moje "dzieło" przez internet, wszystko zaczęłoby się walić. połączenie jest TCP, nieblokujące (a więc teoretycznie wszystko powinno dojść).
moje pytania:
- co może być przyczyną powyższych błędów? czy użycie select pomoże? (teraz mam tylko ignorowanie błędu would block, co podejrzewam, że nie jest dobrym rozwiązaniem, ale wygląda na działające)
- czy znacie jakiś tutorial do Winsocka pisany pod kątem programowania gier lub stworzony w "łopatologiczny" sposób?
z góry dzięki każdemu, kto tu napisze.
« Ostatnia zmiana: Marzec 02, 2010, 23:39:42 wysłana przez Jaklub »

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline BrutalComputer

  • Użytkownik

# Marzec 02, 2010, 23:22:06
Zaznaczam, że na winsock się nie znam.
po około 180 tysiącach poleceń z dlla gra po prostu się wyłączałaNie wiem co to jest, ale może jakiś wyciek pamięci?
czy znacie jakiś tutorial do Winsocka pisany pod kątem programowania gier lub stworzony w "łopatologiczny" sposób?Nie znam tutoriali do winsocka. Jeżeli chodzi o sieć, to w łopatologiczny sposób jest napisana biblioteka SDL_Net. Nigdy nie miałem z nią problemów, zarówno przy TCP jak i UDP. Polecam spróbować przepisać kod na nią.

Offline Esidar

  • Użytkownik

# Marzec 02, 2010, 23:24:52
teraz mam tylko ignorowanie błędu would block
I to może być jedna z przyczyn. Send może się nie udać, jeśli poprzednie pakiety nie zdążyły jeszcze wyjść np. z powodu małego stosu TCP oraz wolnego łącza. Jeżeli np. próbujesz wypchnąć 200kB/s przy łączu 1kB/s to send będzie cały czas zwracał błąd. Wtedy trzeba odczekać chwilę i ponowić wysyłanie pakietu. Aż do skutku.

Offline dannte

  • Użytkownik

# Marzec 02, 2010, 23:30:59
Rozumiem, że już msdna przestudiowałeś? :)
Ale co masz na myśli tutaj:
Cytuj
wczoraj zaobserwowałem, że pakiety od serwera nie dochodzą do klientów kiedy nie są wysyłane w pętli while
bo nie zrozumiałem; w tym wypadku przydałby się jakiś kod (ten działający i ten niedziałający).
No i co stoi na przeszkodzie przed użyciem select?

Pozdro.

Offline Jaklub

  • Użytkownik

# Marzec 02, 2010, 23:36:14
dzięki za odpowiedzi.
Nie wiem co to jest, ale może jakiś wyciek pamięci?
myślę, że to coś w tym stylu, ale nie miałem (i wciąż nie mam) pojęcia, jak sobie z tym poradzić.
Nie znam tutoriali do winsocka. Jeżeli chodzi o sieć, to w łopatologiczny sposób jest napisana biblioteka SDL_Net. Nigdy nie miałem z nią problemów, zarówno przy TCP jak i UDP. Polecam spróbować przepisać kod na nią.
dzisiaj próbowałem to zrobić, ale moje próby kończyły się niepowodzeniem (SDL i Allegro "gryzły" się - redefinicje itp.). czy istnieje możliwość używania SDL_net bez SDLa? (mam nadzieję, że nie wygłupiłem się tym pytaniem)
I to może być jedna z przyczyn. Send może się nie udać, jeśli poprzednie pakiety nie zdążyły jeszcze wyjść np. z powodu małego stosu TCP oraz wolnego łącza. Jeżeli np. próbujesz wypchnąć 200kB/s przy łączu 1kB/s to send będzie cały czas zwracał błąd. Wtedy trzeba odczekać chwilę i ponowić wysyłanie pakietu. Aż do skutku.
wnioskuję, że select może pomóc. jutro, przed próbami przeniesienia projektu, sprawdzę tę metodę.
Rozumiem, że już msdna przestudiowałeś? :)
Ale co masz na myśli tutaj:
Cytuj
wczoraj zaobserwowałem, że pakiety od serwera nie dochodzą do klientów kiedy nie są wysyłane w pętli while
bo nie zrozumiałem; w tym wypadku przydałby się jakiś kod (ten działający i ten niedziałający).
No i co stoi na przeszkodzie przed użyciem select?

Pozdro.
msdn przejrzałem i nie znalazłem rozwiązania mojego problemu, chociaż mogłem je przegapić.
co do niedziałającego kodu (tego, który opisałem jako "poza pętlą while" - kod jest wykonywany przed samą rozgrywką, służy on do przesyłania mapy), wygląda on tak:
                 for(i=1; i<8; i++) {
                          if(playerexists[i]==0) continue;
                          for(p=0; p<=mapsizey; p++) {
                                   ClearBuffer();
                                   WriteInt(6);
                                   WriteInt(p);
                                   for(u=0; u<=mapsizex; u++) {
                                            WriteInt(tile[u][p]);
                                            WriteInt(tilearg[u][p][0]);
                                            WriteInt(tilearg[u][p][1]);
                                            }
                                   u=send(client[i],netbuffer,sizeof(netbuffer),0);
                                   }
                          ClearBuffer();
                          WriteInt(7);
                          for(p=0; p<8; p++) {
                                   WriteInt(bomberman_i[p]);
                                   WriteInt(bomberman_x[p]);
                                   WriteInt(bomberman_y[p]);
                                   }
                          send(client[i],netbuffer,sizeof(netbuffer),0);
                          }
ClearBuffer i WriteInt to moje własne funkcje upraszczające korzystanie z bufora. sam bufor to char[160]
co do funkcji select, jak już pisałem - spróbuję przerobić kod jutro.
« Ostatnia zmiana: Marzec 02, 2010, 23:40:31 wysłana przez Jaklub »

Offline Esidar

  • Użytkownik

# Marzec 03, 2010, 01:04:39
Wysyłasz jakąś straszną liczbę pakietów. Jeśli pchniesz całą mapę kazdy_klient * mapsizex * mapsizex + nagłówki + nagłówki TCP to wyjdzie sporo tego. Nie możesz pchać send bez końca w jednej pętli. Musisz czekać aż wyjdą poprzednie. To oznacza właściwie, wyjście z tej pętli i powrót do niej co jakiś czas, żeby kontynuować.
Jak masz np. neostradę 512kbs to na wyjściu masz tylko 32kbps, czyli możesz wysyłać max 4kB/s... a w takiej jednej pętli to pewnie próbujesz parę kB i to w dużej ilości pakietów (200 ? 400 ?). Generalnie przy tego rodzaju przesyłaniu, używa się np. IOCTL. Wtedy wysyłasz nowy pakiet dokładnie w momencie kiedy wysłany będzie poprzedni. Może to trwać 1-2min, ale nic nie poradzisz.
Po za tym przemyśl, czy na pewno musisz wysyłać mapę przed grą. Jak się podłączy jeden klient z modemem 32kbps to wszyscy będą czekać aż jemu się dociągnie mapa :)
« Ostatnia zmiana: Marzec 03, 2010, 01:06:48 wysłana przez Esidar »

Offline Kuba®'79™

  • Użytkownik

# Marzec 03, 2010, 01:30:38
Nie sprawdzasz rezultatów zwróconych przez senda, więc skąd pomysł, że cokolwiek w ogóle wysłałeś?

To że gniazdko jest nieblokujące znaczy tylko, że send wykona Ci się (prawie) natychmiast, ale nie oznacza, że wykona Ci się z powodzeniem.. Tak jak pisze Esidar: przy tej ilości danych jest nieprawdopodobne, żeby się to udało..


IMVHO najprościej Ci będzie, jeżeli mapę sobie najpierw wrzucisz do jakiegoś bufora i potem będziesz ten bufor wysyłał po kawałku, tzn robisz send całego, ale sprawdzasz, ile na prawdę poszło. Jeżeli nie poszedł cały, to czekasz (np. selectem czy jakąkolwiek inną metodą) aż możesz dalej wysyłać i puszczasz jeszcze raz wszystko od ostatniego niewysłanego bajtu i tak dalej.

Offline Jaklub

  • Użytkownik

# Marzec 03, 2010, 20:20:23
dzięki za kolejne odpowiedzi.
Nie sprawdzasz rezultatów zwróconych przez senda, więc skąd pomysł, że cokolwiek w ogóle wysłałeś?

To że gniazdko jest nieblokujące znaczy tylko, że send wykona Ci się (prawie) natychmiast, ale nie oznacza, że wykona Ci się z powodzeniem.. Tak jak pisze Esidar: przy tej ilości danych jest nieprawdopodobne, żeby się to udało..


IMVHO najprościej Ci będzie, jeżeli mapę sobie najpierw wrzucisz do jakiegoś bufora i potem będziesz ten bufor wysyłał po kawałku, tzn robisz send całego, ale sprawdzasz, ile na prawdę poszło. Jeżeli nie poszedł cały, to czekasz (np. selectem czy jakąkolwiek inną metodą) aż możesz dalej wysyłać i puszczasz jeszcze raz wszystko od ostatniego niewysłanego bajtu i tak dalej.
sprawdzałem rezultaty, jednak wywaliłem to z kodu. nie zwracało żadnego błędu.