[BCB] Czemu ClientSocket dzieli odebrane wiadomości

0

Może po temacie trudno sie domyslić o co w nim chcodzi ale chodzi o to że napisałem sobie programik który na porcie 80 wysyła do serwera jakiejś stronki (np: 4programmers.net) ort! o wysłanie pliku (GET jakis_plik HTTP/1.0\n\n) i czeka na odpowiedz :) W OnRead dla ClientSocket wstawiam kod który pokazuja okienko z wiadomością którą otrzymał (ShowMessage(Socket->ReceiveText());) kompiluje wpisuje adres i wszystkie dane klikam button i robi sie taka dziwna rzecz że odebrany plik pojawia sie w paru okienkach w pierwszym nagłówek i kawałek stronki potem reszta stronki a jak strona jest naprawde rozbudowana to potrafi nawet na 5-8 okienek sie podzielić. Nie wiem czy jest zrozumiałe to co napisałem ale jak temu zaradzić ?? Co mam zrobić żeby wszystko pojawiało sie w jednym okienku ?? Prosze o pomoc :)

0

hehe bo wysyłanie przez internet polega na wysyłaniu pakietami - jeden pakiet może mieć w sobie 65535 bajtów, w tym 40 bajtów :IP_HEADER, 20 bajtów TCP_HEADER.

Odbierając stronkę z localhosta, która ma 3KB - 8 razy mam FD_READ i gromadzę te dane w pamięci
http://free.of.pl/s/sapero/wsc.jpg

Jeśli łącze pomiędzy dwoma komputerami nie jest dobre, to pakiety są małe, nawet po 100 bajtów samych danych :-/
Właśnie piszę "kontrolkę" winsock podobną do tej z VB, tyle że ona sama wie, kiedy nadawca przestał nadawać i wysyła notify do parent window. Każda kontrolka robi niewidzialne child-okienko, ma swojego nieblokującego socketa i zaalokowaną pamięć do której wskaźnik jest w... SetWindowLong(hwnd, GWL_USERDATA, Memo) :)
Memo wskazuje na strukturę zaalokowaną przez malloc() i tam mam wszystko co potrzebne: host, port, socket, ile bajtów wysłałem i odebrałem, wskaźnik do bufora dla odbierania i wysyłania...

Winsock niestety ma taki błąd (albo i nie) że wysyła FD_READ jeśli tylko odbierze ileśtam danych. Fajnie by było gdyby to robił tylko dla pełnego bufora, np 64kB.
Innym problemem, z którym się borykałem kilka godzin, jet to że odbierając stronkę z jakiegoś szybkiego serwera, tuż pod koniec odbierania serwer wysyła FD_CLOSE, ale potem karta sieciowa jeszcze odbiera paczki z danymi!! Więc reagowanie na FD_CLOSE darowałem sobie, uruchomiłem timera 100ms dla odbioru (skakał do funkcji odbierającej) i sprawdzam błędy odbioru

received = recv(Memo.sock, Memo.pData, Memo.DataLen)
wsaerror = WSAGetLastError()
IF (received = 0) or (wsaerror = WSAENOTCONN)
//wyślij notyfikację że dane są odebrane i zamknij socket

jeśli nie było błędu

Memo.pData += received
Memo.DataLen -= received
if (Memo.DataLen=0) // bufor pełny
  wscNotify(Memo, NM_BUFFER_FULL) // wysyła WM_NOTIFY
  // przesuwam pData na początek bufora
  Memo.pData   = Memo.ConstPdata
  Memo.DataLen = Memo.ConstDataLen
  // i czekam dalej na dane

A zatem jeśli odbierasz dane ze strony - gromadź odebrane dane do jakiegoś bufora i dopiero jak dostaniesz z socketa CLOSE albo WRITE to je pokaż

0

Radzę wam obu przeczytać WinSock Programmers FAQ
http://tangentsoft.net/wskfaq/

w temacie:
"Assuming stream sockets maintain message frame boundaries. Mind bogglingly lame.
Reason: Stream sockets (TCP) are called stream sockets, because they provide data streams (duh). As such, the largest message size an application can ever depend on is one-byte in length. No more, no less. This means that with any call to send() or recv(), the Winsock implementation may transfer any number of bytes less than the buffer length specified."

I oczywiście o HTTP, bo tam jest troszkę zamieszane z długością przesyłanych danych, line-break na końcach linii ale kontrola ilości danych przez wpisy w nagłówkach HTTP, itp. :>

0

ludzie, on pisze o TClientSocket :-/ a nie winsockach

masz ten walek, ze TClientSocket paczkuje dane po 8kb, wiec musisz te dane zbierac do kupy i potem polaczyc.

0

Ok rozwiązałem to w dość banalny ale mam nadzieje że skuteczny sposób. Tworzę TStringList i w OnRead daje Lista->Lines->Add(Socket->ReceiveText()); :)

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