WinSock - kilka pytań

0

Witam.
Dopiero zaczynam przygodę z WinSock i już zaczynam się gubić:

  1. Skąd mam wiedzieć czy funkcja connect() zakończyła się pomyślnie jeżeli w trybie nieblokującym zwraca WSAEWOULDBLOCK? dokładniej to chciałbym mieć możliwośc sprawdzenia czy udało się połączyć, a jeżeli nie to byłoby miło poznać błąd.
  2. Jak poprawnie rozłączyć połączenie, tak by móc dalej ponownie połączyć się tym samym gniazdem np. z innym adresem.
  3. Wiecie może o jakiejś klasie obudowującej WinSock, tak by było dużo łatwiej z niego korzystać?
0
  1. WSAEWOULDBLOCK oznacza ze operacja leci rownolegle do programu (w tle) i jeszcze sie nie zakonczyla. musisz w terminie pozniejszym odpytac o jej stan i dopiero wtedy dostaniesz info czy SUCC/FAIL

  2. nie wiem czy dobrze rozumiem pytanie, ale nie mozna, bo to nie tak dziala. w modelu polaczen klient/serwer masz 1+2n gniazd. serwer otwiera 1 gniazdo na ktorym slucha czy ktos chcialby sie polaczyc, w momencie gdy ktos sie polaczy do niego, serwer natychmiast "klonuje" to gniazdo i na starym gniezdzie dalej slucha na nastepnych klientow, zas klona uzywa do komunikacji z owym nowym klientem. [stad: 1gniazdo nasluchowe + n(gniazdo komunikacyjne serwera+gniazdo kom. klienta)]. gniazda komunikacyjne serwera/klienta sluza tylko do rozmawiania z danym serwerem/klientem i po tym jak polaczenie zostanie zerwane nie nadaja sie juz do niczego -- absolutnie trzeba utworzyc nowa pare zeby rozmawiac z kims nowym [w modelu klient-serwer nowa para 'sama sie' stworzy i tak]. odpowiadajac zas wprost na pierwsza czesc pytania: do grzecznego, ladnego, czystego zamykania polaczenia sluzy para: shutdown() czyli poinformowanie o zakmnieciu strumieni i potem close() aby 'usunac' socket [pare socket()/close() traktuj jak new/delete albo malloc/free. to shutdown zamyka polaczenie. close je zrywa]

  3. praktycznie kazdy framework ma cos takiego..

0
  1. Dzięki WSAAsyncSelect Twoje okno może odbierać powiadomienia o zmianie stanu socketu.
    Dzięki WSAEventSelect i select możesz periodycznie/stale oczekiwać przez dowolny czas na te zmiany.
    Socket z ustawioną flagą overlapped zgłasza zmianę stanu ustawiając event, na który łatwo się czeka nawet w pętli odbierającej komunikaty okien (MsgWaitForMultipleObjects), lub instalując callback funkcją RegisterWaitForSingleObject.

Może uzupełnię punkt 2.
Połączony socket zawsze jest 'podpięty' do stałego portu. Port ten wybiera system podczas operacji connect(), lub user, funkcją bind(). Zdalny komputer wysyła dane na ten właśnie port, dlatego wiadomo do którego socketu wpisać odebrane dane.

W momencie rozłączenia połączenia, socket, a raczej lokalny port zajęty przez niego przechodzi na własność systemu by zapewnić protokołowową procedurę rozłączenia. Gdy Ty pierwszy się rozłączysz funkcją closesocket, system szybko wysyła pakiet FIN i zaczyna oczekiwać dobre kilkadziesią sekund na potwierdzenie z drugiej strony kabla, co jakiś czas ponawiając wysłanie pakietu FIN gdy nie ma odpowiedzi.

Dlatego nie możesz użyć tego samego socketu. Sockety są tak zaprojektowany by nie dało się im zmienić ani portów, ani żadnego z dwóch IP. Z góry założono, że zakończenie rozłączenia potrwa długo.

0
sapero napisał(a)
  1. Dzięki WSAAsyncSelect Twoje okno może odbierać powiadomienia o zmianie stanu socketu.
    Dzięki WSAEventSelect i select możesz periodycznie/stale oczekiwać przez dowolny czas na te zmiany.
    Socket z ustawioną flagą overlapped zgłasza zmianę stanu ustawiając event, na który łatwo się czeka nawet w pętli odbierającej komunikaty okien (MsgWaitForMultipleObjects), lub instalując callback funkcją RegisterWaitForSingleObject.
    Dobra, jeszcze jakby wiedział o czym do mnie mówisz to byłoby dobrze :-D programuje od niedawna, i chwilowo siedzę w konsoli, a te funkcje jak MsgWaitForMultipleObjects pachną mi GUI już. Ale przyjżę się im. :) a póki co chyba skorzystam z select() tylko jeszcze doczytam na msdn z czym to sie je ;-P
sapero napisał(a)

Może uzupełnię punkt 2.
Połączony socket zawsze jest 'podpięty' do stałego portu. Port ten wybiera system podczas operacji connect(), lub user, funkcją bind(). Zdalny komputer wysyła dane na ten właśnie port, dlatego wiadomo do którego socketu wpisać odebrane dane.
(...)
Dlatego nie możesz użyć tego samego socketu. Sockety są tak zaprojektowany by nie dało się im zmienić ani portów, ani żadnego z dwóch IP. Z góry założono, że zakończenie rozłączenia potrwa długo.
Czyli mam rozumieć że coś takiego nie przejdzie:

SOCKET sock;
sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
connect(sock, addr, sizeof(addr));
shutdown( sock, SD_SEND );
closesocket( sock );

sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
connect(sock, addr, sizeof(addr)); // próba połączenia z innym IP
0

Źle mnie zrozumiałeś. Tworzysz nowy socket, łączysz się i zamykasz socket+połączenie. Następnie tworzysz nowy socket, który zadziała tak samo jak poprzedni, przecież jest w całkiem surowym stanie.

Pierwszy socket zaraz po zamknięciu (closesocket) przestaje istnieć w aplikacji, ale istnieje jeszcze przez jakiś czas w w systemie by zapewnić protokołowe wiesz co. Ponowne wywołanie funkcji socket tworzy zupełnie nowy obiekt, z którym można zrobić to samo co z poprzednim.

A to shutdown bezpośrednio przed closesocket jest całkowicie zbyteczne, można tego użyć gdy masz jakąś skomplikowaną pętlę która coś robi po odebraniu/wysłaniu pakietu, a szkoda Ci komplikować kod by gdzieś dodać zmienną typu "ignoruj recv lub send" i jeszcze jednego IF zaraz za recv() / przed send().
Albo masz dwa wątki - jeden ciągle wysyła, drugi wisi czekając na dane. Nie chcesz już odbierać danych, ale masz coś do wysłania - shutdown tutaj pasuje, jeden wątek dostanie błąd i się odpętli.

0
sapero napisał(a)

Źle mnie zrozumiałeś.
Całkiem możliwe :) ale teraz już rozumiem, system trzyma gniazdo dla siebie żeby wszystko ładnie zakończyć, a ja w programie mogę znowu użyć zmiennej SOCKET do łączenia się. Wielkie dzięki za pomoc. Może na razie wystarczy :-P

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