Wednesday, 29 November 2017

Winsock send data binary options


Wysyłanie danych binarnych za pośrednictwem protokołu UDP (Winsock) Tworzę program klienta, który wymaga danych binarnych, które mają być wysyłane na serwer za pośrednictwem protokołu UDP. (Im przy użyciu kontroli winsock) Użyłem następującego kodu. Dim ByteX jako Byte Dim X jako Long Dim FileX jako Interger Winsock3.LocalPort 10000 Winsock3.RemoteHost 211.233.70.51 Winsock3.RemotePort 9500 FileX FreeFile Otwórz App. Path udp1.dat dla Binary jako FileX X 1 Do Ukończ X FileLen (App. Path udp1.dat) 1 Uzyskaj FileX. X, ByteX Winsock3.SendData ByteX X X 1 Loop Zamknij FileX Kiedy wysyłam dane w ten sposób, wysyła on 52 pakiety zawierające 1 bajt każdy zamiast jednego pakietu zawierającego 52 bajty. Ten kod działa poprawnie dla protokołu TCP, ale UDP nie działa tak samo. Jak mogę wysyłać dane binarne za pomocą protokołu UDP, który będzie wysyłać tylko 1 pakiet danych Robię program kliencki, który wymaga danych binarnych do wysłania na serwer za pośrednictwem protokołu UDP. (Im przy użyciu kontroli winsock):: Ive był przy użyciu następującego kodu. :: Dim ByteX jako Byte: Dim X tak długo: Dim FileX jako Interger:: Winsock3.LocalPort 10000: Winsock3.RemoteHost 211.233.70.51: Winsock3.RemotePort 9500:: FileX FreeFile: Otwórz App. Path udp1.dat dla pliku binarnego jako FileX : X 1: Czy Do X FileLen (App. Path udp1.dat) 1: Pobierz FileX. X, ByteX: Winsock3.SendData ByteX: X X 1: Loop: Close FileX:: Kiedy wysyłam dane w ten sposób, wysyła on 52 pakiety zawierające 1 bajt każdy zamiast jednego pakietu zawierającego 52 bajty. Ten kod działa poprawnie dla protokołu TCP, ale UDP nie działa tak samo. Jak mogę wysyłać dane binarne za pomocą protokołu UDP, który będzie wysyłać tylko 1 pakiet danych: Hi Spróbuj tego Winsock3.Protocol sckUDPProtocol Winsock ma domyślnie sckTCPProtocol .. purpleDont wziąć życie zbyt poważnie i tak nie ujdziesz żywcem z itpurplesending danych binarnych za pomocą winsock Im przepraszam, czy mówisz, że muszę korzystać z Datagram zamiast Stream Sockets, aby mieć tę pracę Używam teraz SOCKSTREAM i wolałbym pozostać przy tym. Czy jest jakiś sposób na uzyskanie tego, aby zaakceptować 0x00 i zaakceptować dane po nim, przy jednoczesnym użyciu gniazd strumieniowych. Jeszcze raz, dzięki za twoją pomoc. mikyu Hmm, to dziwne. Myślałem, że argument SOCKDGRAM powinien określać dane binarne, w przeciwieństwie do SOCKSTREAM. : W tym przypadku recv powinien przeczytać więcej niż zero. : Jesteś pewien, że nie przechwytujesz danych w typach łańcuchowych, które drukujesz lub zapisujesz do pliku lub czegoś z jedną z procedur str: Mam na myśli, czy jesteś pewien, że poprawnie wyświetlasz odebrane dane Przepraszam, czy mówisz, że muszę korzystać z Datagram zamiast Stream Sockets, aby mieć tę pracę? Używam teraz SOCKSTREAM i wolałbym pozostać przy tym. Czy jest jakiś sposób na uzyskanie tego, aby zaakceptować 0x00 i zaakceptować dane po nim, przy jednoczesnym użyciu gniazd strumieniowych. Jeszcze raz, dzięki za twoją pomoc. : mikyu:. Hmm, to dziwne. Myślałem, że argument SOCKDGRAM powinien określać dane binarne, w przeciwieństwie do SOCKSTREAM. . W tym przypadku recv powinien przeczytać więcej niż zer. . Jesteś pewny, że nie przechwytujesz danych w typach łańcuchowych, które drukujesz lub zapisujesz do pliku lub czegoś z jedną z procedur str.? Mam na myśli, czy jesteś pewien, że poprawnie wyświetlasz odebrane dane: SOCKDGRAM nie oznacza danych binarnych. Oznacza to, że chcesz używać protokołu UDP do wysyłania danych, a dane są wysyłane w datagramach. SOCKSTREAM oznacza, że ​​chcesz używać protokołu TCP i wysyłać dane jako strumień. Gniazdo nie obchodzi, jakiego rodzaju dane wysyłasz. Wszystko czego potrzebujesz to wskaźnik do bufora, który przechowuje dane i długość tego bufora. Zero danych wewnątrz nic nie znaczy, to tylko zero. Dane nie są kończone przez zero, ponieważ są to ciągi znaków C. Gniazdo nie dba o zawartość danych. Myślę, że coś jest nie tak z twoim kodem. Być może używasz zera jako terminatora, co jest bardzo złe. Jeśli mógłbyś opublikować kod, który odbiera dane tutaj, mógłbym spróbować dowiedzieć się, co jest z nim nie tak. Oto kod, którego używam. Ponownie, jestem nowy w winsock, więc proszę o zachowanie mnie. Kod dzięki int serwer (void) unsigned char recmsg3072 SOCKET serverfd, clientfd nasłuch na sockfd, nowe połączenie na newfd SOCKADDRIN serveraddr SOCKADDRIN clientaddr int len ​​int j int msgsize 0 char pytanie WSADATA wsadata unsigned short verrequest PLIK MIKA LINGER LingVar verrequest MAKEWORD (2,2 ) if (WSAStartup (verrequest, ampwsadata) -1) printf (Couldnt find usingable Winsock DLL) exit (1) if ((serverfd socket (AFINET, SOCKSTREAM, 0)) -1) perror (SERVER SIDE: nie można otworzyć gniazda) LingVar. lonoff TRUE LingVar. llinger 0 jeśli (setsockopt (serverfd, SOLSOCKET, SOOOBINLINE, (char FAR) ampLingVar, sizeof (LingVar)) -1) perror (SERVER SIDE: couldnt wykonać setsockopt) exit (1) serveraddr. sinfamily AFINET serveraddr. sinport htons (SERVERPORT) serveraddr. sinaddr. saddr htonl (INADDRANY) memset (amp (serveraddr. sinzero),, 8) if (bind (serverfd, (struct sockaddr) ampserveraddr, sizeof (serveraddr)) -1) perror (SERVER SIDE: nie można powiązać portu) exit (1) if (listen (serverfd, PACKETQUEUE) -1) per ror (SERVER SIDE: nie można słuchać gniazda) exit (1) memset (recmsg, 0x0, 3072) while (1) printf (Czy chcesz kontynuować (YN)) pytanie getchar () jeśli (pytanie) pytanie getchar () jeśli (pytanie N pytanie n) return 0 printf (SERVER SIDE: Oczekiwanie na Dane na porcie) len sizeof (clientaddr) clientfd accept (serverfd, (struct sockaddr) ampclientaddr, amplen) jeśli (clientfd -1) perror (SERVER SIDE: nie może zaakceptować połączenie) return ERROR printf (SERVER SIDE: odebrane połączenie z: s, inetntoa (clientaddr. sinaddr)) msgsize readline (recmsg, clientfd, clientaddr) jeśli (msgsize ERROR) printf (SERVER SIDE: nie można odczytać wiadomości) coutltltthis to rozmiar wiadomości : ltltmsgsizeltltendl fwrite (recmsg, sizeof (short int), 10, mike) dla (j0 jlt10 j) printf (- c, recmsgj) closesocket (clientfd), jeśli zakończono (WSACleanup () -1) perror (problem z WSACLEANUP) ( 1) int readline (unsigned char buf, SOCKET sd, clientADdr SOCKADDRIN) char segMAXDATA int przesunięcie 0 int res 1 int cliLen memset (seg, 0x0, MAXDATA) cliL en sizeof (clientaddr) while ((res recvfrom (sd, seg, MAXDATA, 0, (struct sockaddr) ampclientaddr, ampcliLen)) SOCKETERROR) if (resEOFresWSAECONNRESETresWSAECONNABORTED) 0inne boczne zakończone połączenie printf (połączenie zakończone przez klienta) return offset memcpy (bufoffset, seg, res) offset res memset (seg, 0x0, MAXDATA) return ERROR code: SOCKDGRAM nie oznacza danych binarnych. Oznacza to, że chcesz używać protokołu UDP do wysyłania danych, a dane są wysyłane w datagramach. SOCKSTREAM oznacza, że ​​chcesz używać protokołu TCP i wysyłać dane jako strumień. :: Gniazdo nie obchodzi, jakiego rodzaju dane wysyłasz. Wszystko czego potrzebujesz to wskaźnik do bufora, który przechowuje dane i długość tego bufora. :: Zero wewnątrz danych nic nie znaczy, to tylko zero. Dane nie są kończone przez zero, ponieważ są to ciągi znaków C. Gniazdo nie dba o zawartość danych. :: Myślę, że coś jest nie tak z twoim kodem. Być może używasz zera jako terminatora, co jest bardzo złe. Jeśli mógłbyś opublikować kod, który odbiera dane tutaj, mógłbym spróbować dowiedzieć się, co jest z nim nie tak. : Wprowadzenie do programowania Socket systemu Windows za pomocą C Co mamy w tym rozdziale 1 część 4 Przesyłanie danych send () i WSASend () WSASendDisconnect () Out-of-Band Data recv () i WSARecv () WSARecvDisconnect () Stream Protocols Scatter - Gather IO Breaking the Connection shutdown () closesocket () TCP ReceiverServer Z select () Przykład Transmisja danych send () i WSASend () WSASendDisconnect () Out-of-Band Data recv () i WSARecv () Żądanie odbioru zakończy się tylko gdy wystąpi jedno z następujących zdarzeń: Bufor dostarczony przez wywołującego jest całkowicie pełny. Połączenie zostało zamknięte. Żądanie zostało anulowane lub wystąpił błąd. Zauważ, że jeśli podstawowy transport nie obsługuje MSGWAITALL, lub jeśli gniazdo jest w trybie bez blokady, to połączenie nie powiedzie się z WSAEOPNOTSUPP. Ponadto, jeśli MSGWAITALL zostanie określony razem z MSGOOB, MSGPEEK lub MSGPARTIAL, to połączenie nie powiedzie się z WSAEOPNOTSUPP. Ta flaga nie jest obsługiwana na gniazdach datagramowych lub gniazdach zorientowanych komunikacyjnie. Oczywiście 0 nie określa żadnych specjalnych działań. MSGPEEK powoduje, że dane dostępne do skopiowania do dostarczonego bufora odbiorczego. ale te dane nie są usuwane z bufora systemowego. Zwracana jest także liczba oczekujących bajtów. Podgląd wiadomości jest zły. Nie tylko obniża wydajność, ponieważ teraz trzeba wykonać dwa wywołania systemowe (jeden do podglądu i jeden bez flagi MSGPEEK, aby faktycznie usunąć dane), ale jest także niewiarygodny w pewnych okolicznościach. Zwrócone dane mogą nie odzwierciedlać całej dostępnej kwoty. Ponadto, pozostawiając dane w buforach systemowych, system ma mniej miejsca na dane przychodzące. W rezultacie system zmniejsza rozmiar okna TCP dla wszystkich nadawców. Zapobiega to osiągnięciu przez aplikację maksymalnej możliwej przepustowości. Najlepszą rzeczą do zrobienia jest skopiowanie wszystkich danych do własnego bufora i manipulowanie nim w tym miejscu. Istnieje kilka uwag dotyczących korzystania z funkcji recv () na gnieździe opartym na komunikacie lub datagramie, takim jak UDP, który opiszemy później. Jeśli oczekujące dane są większe niż dostarczony bufor, bufor jest wypełniony tak dużą ilością danych, jakie będzie zawierać. W tym przypadku wywołanie recv () generuje błąd WSAEMSGSIZE. Zwróć uwagę, że błąd rozmiaru wiadomości występuje w przypadku protokołów zorientowanych na komunikat. Protokoły strumieniowe, takie jak buforowe dane przychodzące TCP, zwracają tyle danych, ile żąda aplikacja, nawet jeśli ilość oczekujących danych jest większa. Dlatego w przypadku protokołów strumieniowych nie napotkasz błędu WSAEMSGSIZE. Funkcja WSARecv () dodaje kilka nowych możliwości w stosunku do recv (), takich jak nakładające się komunikaty IO i częściowe powiadomienia datagramowe. Definicja WSARecv () to: Parametr s jest połączonym gniazdem. Drugi i trzeci parametr to bufory do odbioru danych. Parametr lpBuffers jest tablicą struktur WSABUF, a dwBufferCount wskazuje liczbę struktur WSABUF w tablicy. Parametr lpNumberOfBytesReceived wskazuje na liczbę bajtów odebranych przez to połączenie, jeśli operacja odbierania zakończy się natychmiast. Parametr lpFlags może być jedną z wartości MSGPEEK, MSGOOB lub MSGPARTIAL, lub bitową kombinacją LUB tych wartości. Flaga MSGPARTIAL ma kilka różnych znaczeń w zależności od miejsca, w którym jest używana lub napotkana. W przypadku protokołów zorientowanych na komunikaty, które obsługują częściowe przesyłanie wiadomości (np. AppleTalk), ta flaga jest ustawiana po powrocie z usługi WSARecv () (jeśli nie można zwrócić całej wiadomości w tym wywołaniu z powodu niewystarczającego miejsca w buforze). W takim przypadku późniejsze wywołania WSARecv () ustawiają tę flagę, dopóki cała wiadomość nie zostanie zwrócona, gdy flaga MSGPARTIAL zostanie wyczyszczona. Jeśli ta flaga zostanie przekazana jako parametr wejściowy, operacja odbierania powinna zakończyć się, gdy tylko dane będą dostępne, nawet jeśli jest to tylko część całej wiadomości. Flaga MSGPARTIAL jest używana tylko z protokołami zorientowanymi na komunikaty, a nie strumieniowymi. Ponadto nie wszystkie protokoły obsługują częściowe wiadomości. Wpis protokołu dla każdego protokołu zawiera flagę wskazującą, czy obsługuje tę funkcję. Parametry lpOverlapped i lpCompletionRoutine są używane w nakładających się operacjach IO omówionych w innym rozdziale. Jest jeszcze jedna specjalistyczna funkcja odbierająca, o której powinieneś wiedzieć: WSARecvDisconnect (). WSARecvDisconnect () Ta funkcja jest przeciwieństwem WSASendDisconnect () i jest zdefiniowana następująco: int WSARecvDisconnect (SOCKET s, LPWSABUF lpInboundDisconnectData) Podobnie jak jego odpowiednik wysyłający, parametry WSASendDisconnect () są połączonym uchwytem gniazda i prawidłową strukturą WSABUF z dane do odbioru. Otrzymane dane mogą jedynie rozłączać dane wysyłane przez WSASendDisconnect (), z drugiej strony nie można ich użyć do odbioru normalnych danych. Ponadto, po odebraniu danych, ta funkcja wyłącza odbiór od strony zdalnej, co jest równoważne wywołaniu funkcji shutdown () (opisanej później) z SDRECEIVE. Protokoły strumieniowe Ponieważ większość komunikacji zorientowanych na połączenie, takich jak TCP, to protokoły transmisji strumieniowej, krótko opisz je tutaj. Protokół przesyłania strumieniowego to taki, który nadawca i odbiorca mogą rozpaść lub połączyć dane w mniejsze lub większe grupy. Poniższy rysunek opisuje pokrótce przepływ pakietu TCP między stronami klienta i serwera. Główną rzeczą, o której należy pamiętać przy każdej funkcji, która wysyła lub odbiera dane w gnieździe strumieniowym, jest to, że nie można zagwarantować, że odczytasz lub zapiszesz żądaną ilość danych. Powiedzmy, że masz bufor znaków z 2048 bajtami danych, które chcesz wysłać za pomocą funkcji wysyłania. Kod do wysłania to: int nBytes 2048 Wypełnij sendbuff z 2048 bajtami danych Załóżmy, że s jest poprawnym, połączonym przesyłaniem strumienia gniazda send send (s, sendbuff, nBytes, 0) Możliwe jest wysyłanie, aby powrócić po wysłaniu mniej niż 2048 bajtów . Zmienna ret zostanie ustawiona na liczbę wysłanych bajtów, ponieważ system przydziela pewną ilość przestrzeni buforowej dla każdego gniazda do wysyłania i odbierania danych. W przypadku wysyłania danych, wewnętrzne bufory przechowują dane, które mają być wysłane, aż do momentu, w którym dane mogą zostać umieszczone na drucie. Może to spowodować kilka typowych sytuacji. Na przykład, po prostu przesłanie ogromnej ilości danych spowoduje szybkie wypełnienie tych buforów. Ponadto, dla TCPIP, istnieje tak zwany rozmiar okna (demonstracja okna przesuwnego). Koniec odbiorczy dostosuje rozmiar okna, aby wskazać, ile danych może otrzymać. Jeśli odbiornik jest zalewany danymi, może ustawić rozmiar okna na 0, aby nadążyć za oczekującymi danymi. To zmusi nadawcę do zatrzymania się, dopóki nie otrzyma nowego rozmiaru okna większego niż 0. W przypadku naszego wywołania, może istnieć przestrzeń buforowa do przechowywania tylko 1024 bajtów, w takim przypadku będziesz musiał ponownie przesłać pozostałe 1024 bajty. Poniższy kod zapewnia, że ​​wszystkie twoje bajty są wysyłane: int nBytes 2048, nLeft, idx Wypełnij sendbuff z 2048 bajtami danych, podczas gdy (nLeft gt 0) Załóżmy, że s jest prawidłowym, podłączonym gniazdem strumieniowym Rzeczy się komplikują, jeśli rozmiar wiadomości jest inny . Konieczne jest narzucenie własnego protokołu, aby odbiorca wiedział, jak duży będzie nadchodzący komunikat. Na przykład pierwsze cztery bajty zapisane w odbiorniku będą zawsze wielkością całkowitą w bajtach nadchodzącej wiadomości. Odbiornik rozpocznie każdy odczyt, patrząc na pierwsze cztery bajty, konwertując je na liczbę całkowitą i określając liczbę dodatkowych bajtów, które zawiera wiadomość. Obsługa Scatter-Gather IO Scatter-gather to koncepcja pierwotnie wprowadzona w Berkeley Sockets z funkcjami recv i writev. Ta funkcja jest dostępna z funkcjami Winsock 2: WSARecv (), WSARecvFrom (), WSASend () i WSASendTo (). Jest to najbardziej przydatne w przypadku aplikacji, które wysyłają i odbierają dane sformatowane w bardzo specyficzny sposób. Na przykład wiadomości od klienta do serwera zawsze mogą składać się ze stałego 32-bajtowego nagłówka określającego pewną operację, po którym następuje 64-bajtowy blok danych i zakończony 16-bajtowym zwiastunem. W tym przykładzie funkcja WSASend () może zostać wywołana z tablicą trzech struktur WSABUF, z których każda odpowiada trzem typom komunikatów. Na odbierającym końcu wywoływana jest funkcja WSARecv () z trzema strukturami WSABUF, z których każda zawiera bufory danych o długości 32 bajtów, 64 bajty i 16 bajtów. Podczas korzystania z gniazd strumieniowych operacje zbierania rozproszonego traktują dostarczone bufory danych w strukturach WSABUF jako jeden ciągły bufor. Ponadto połączenie odbierające może wrócić, zanim wszystkie bufory będą pełne. W przypadku gniazd opartych na komunikatach każde wywołanie operacji odbioru odbiera pojedynczą wiadomość aż do dostarczonego rozmiaru bufora. Jeśli przestrzeń buforowa jest niewystarczająca, wywołanie kończy się niepowodzeniem z WSAEMSGSIZE, a dane są obcinane w celu dopasowania do dostępnego miejsca. Oczywiście w przypadku protokołów obsługujących częściowe komunikaty można użyć flagi MSGPARTIAL, aby zapobiec utracie danych. Przerywanie połączenia Po zakończeniu połączenia z gniazdem należy je zamknąć i zwolnić zasoby powiązane z tym uchwytem gniazda. Aby faktycznie zwolnić zasoby związane z otwartym uchwytem gniazda, użyj wywołania closesocket (). Należy jednak pamiętać, że funkcja closesocket () może mieć pewne niepożądane skutki, w zależności od tego, jak jest wywoływana, co może prowadzić do utraty danych. Z tego powodu połączenie powinno zostać zakończone z wdzięcznością funkcją shutdown () przed wywołaniem funkcji closesocket (). Te dwie funkcje API są omówione poniżej. shutdown () Aby upewnić się, że wszystkie dane, które wysyła aplikacja, zostały odebrane przez peera, dobrze napisana aplikacja powinna powiadomić odbiorcę, że nie ma już żadnych danych do wysłania. Podobnie, peer powinien zrobić to samo. Jest to znane jako pełne zamknięcie i jest wykonywane przez funkcję shutdown () zdefiniowaną jako: int shutdown (SOCKET s, int how) Jak parametr może być SDRECEIVE, SDSEND lub SDBOTH. W przypadku polecenia SDRECEIVE późniejsze wywołania funkcji odbierania na gnieździe są niedozwolone. Nie ma to wpływu na niższe warstwy protokołów. A w przypadku gniazd TCP, jeśli dane są ustawiane w kolejce do odbioru lub dane przychodzą później, połączenie jest resetowane. Jednak na gniazdach UDP przychodzące dane są nadal akceptowane i kolejkowane (ponieważ shutdown () nie ma znaczenia dla protokołów bezpołączeniowych). W przypadku SDSEND późniejsze wywołania dowolnej funkcji wysyłania są niedozwolone. W przypadku gniazd TCP powoduje to wygenerowanie pakietu FIN po przesłaniu i potwierdzeniu wszystkich danych przez odbiornik. Na koniec, określenie SDBOTH wyłącza wysyłanie i odbiera. Zauważ, że nie wszystkie protokoły zorientowane na połączenie obsługują pełne zamknięcie, co ma miejsce w przypadku funkcji shutdown (). Dla tych protokołów (takich jak ATM), tylko closesocket () musi być wywołany, aby zakończyć sesję. Flaga opisująca typy operacji podsumowane w poniższej tabeli. Możliwe wartości tej flagi są wymienione w pliku nagłówkowym Winsock2.h. Po wywołaniu funkcji shutdown () w celu wyłączenia wysyłania, odbierania lub obu, nie ma metody ponownego włączenia wysyłania lub odbierania dla istniejącego połączenia z gniazdem. Aplikacja nie powinna polegać na możliwości ponownego użycia gniazda po jego wyłączeniu. W szczególności dostawca gniazd systemu Windows nie musi obsługiwać funkcji connect () na wyłączonym gnieździe. Jeśli aplikacja chce ponownie użyć gniazda, należy wywołać funkcję DisconnectEx () z parametrem dwFlags ustawionym na TFREUSESOCKET, aby zamknąć połączenie w gnieździe i przygotować uchwyt gniazda do ponownego użycia. Po zakończeniu żądania DisconnectEx () uchwyt gniazda można przekazać do funkcji AcceptEx () lub ConnectEx (). Jeśli aplikacja chce ponownie użyć gniazda, funkcje TransmitFile () lub TransmitPackets () można wywołać za pomocą zestawu parametrów dwFlags z TFDISCONNECT i TFREUSESOCKET, aby rozłączyć się po tym, jak wszystkie dane zostały umieszczone w kolejce do transmisji i przygotować uchwyt gniazda do ponownego użycia. Po zakończeniu żądania TransmitFile () uchwyt gniazda może zostać przekazany do wywołania funkcji używanego wcześniej do ustanowienia połączenia, takiego jak AcceptEx () lub ConnectEx (). Po zakończeniu funkcji TransmitPackets () uchwyt gniazda można przekazać do funkcji AcceptEx (). Zauważ, że rozłączenie poziomu gniazd zależy od zachowania podstawowego transportu. Na przykład gniazdo TCP może podlegać warunkowi TCP TIMEWAIT, powodując opóźnienie wywołania DisconnectEx (), TransmitFile () lub TransmitPackets (). closesocket () Funkcja closesocket () zamyka gniazdo i jest zdefiniowana jako: int closesocket (SOCKET s) Jeśli nie wystąpi błąd, closesocket () zwraca zero. W przeciwnym razie zwracana jest wartość SOCKETERROR, a konkretny kod błędu można pobrać, wywołując funkcję WSAGetLastError (). Gniazdo jest oznaczone jako niezablokowane, ale element lloff w strukturze lingerowania jest ustawiony na niezerowy, a element llingera struktury zwłoki jest ustawiony na niezerową wartość timeout. Wywołanie closesocket () powoduje zwolnienie deskryptora gniazda, a dalsze wywołania za pomocą gniazda kończą się niepowodzeniem z WSAENOTSOCK. Jeśli nie ma innych odniesień do tego gniazda, wszystkie zasoby powiązane z deskryptorem są zwalniane. Obejmuje to odrzucanie wszelkich danych w kolejce. Oczekujące wywołania synchroniczne wydane przez dowolny wątek w tym procesie są anulowane bez publikowania jakichkolwiek powiadomień. Oczekujące operacje nakładające się również zostaną anulowane. Każde zdarzenie, procedura zakończenia lub port zakończenia powiązany z operacją nakładania zostanie wykonany, ale zakończy się niepowodzeniem z błędem WSAOPERATIONABORTED. Ponadto jeden inny czynnik wpływa na zachowanie closesocket (): czy została ustawiona opcja gniazda SOLINGER. Aplikacja powinna zawsze mieć pasujące wywołanie do closesocket () dla każdego udanego połączenia z gniazdem, aby zwrócić zasoby gniazda do systemu. TCP ReceiverServer Za pomocą select () Przykład 1. Będąc w Visual C IDE, kliknij menu Plik gt podmenu Projekt, aby utworzyć nowy projekt. 2. Wybierz Win32 dla typów Project: i Win32 Console Application for the Templates. Wpisz nazwę projektu i rozwiązania. W razie potrzeby dostosuj lokalizację projektu i kliknij OK. 3. Kliknij przycisk Dalej, aby przejść do strony przeglądu Kreatora aplikacji systemu Win32. Usuniemy wszystkie niepotrzebne elementy projektu. 4. Na stronie Aplikacja wybierz opcję Pusty projekt dla opcji dodatkowych. Pozostaw inne, tak jak podano, i kliknij przycisk Zakończ. 5. Następnie musimy dodać nowy plik źródłowy. Kliknij menu Projekt gt Dodaj nowy element lub wybierz folder projektu w Eksploratorze rozwiązań gt Wybierz Dodaj menu gt Wybierz podmenu Nowa pozycja. 6. Wybierz plik C (.cpp) dla szablonów. Wpisz nazwę pliku źródłowego i kliknij Dodaj. Chociaż rozszerzenie to. cpp, Visual C IDE rozpozna, że ​​użyty kod źródłowy to C na podstawie opcji Kompiluj jako kod C (TC), która zostanie ustawiona na stronie właściwości projektu później. 7. Teraz dodaj kod źródłowy, jak podano poniżej. Przykład zwracanej wartości select () int recvTimeOutTCP (gniazdo GNIAZDO, dłuższa sekunda, długi czas użycia)

No comments:

Post a Comment