2013-05-25 37 views
5

Pracuję nad dość prostą aplikacją klienta/serwera i mam pewne problemy z otrzymywaniem TStringStream od klienta przy użyciu recv dostarczonego przez interfejs API winsock.
Ciągle pojawia się ten błąd: "naruszenie zasad dostępu pod adresem 0x00000000: odczyt adresu 0x00000000".
Klient kopiuje tylko tekst do TStringStream, pobiera jego długość i wysyła go na serwer. Następnie serwer odbiera Stream i wypisuje jego tekst. Poniżej kilka fragmentów kodu abstrakcyjnego.TStringStream ulega uszkodzeniu po odebraniu przy użyciu recv (winsock)?

{ the server's part } 
inBuf := TStringStream.Create; 
{ MAKE THIS SOCKET A PASSIVE ONE } 
    listen(serversock, LISTENQ); 
{ ACCEPT CONNECTION ON serversock FROM cliaddr -> CONNECTED SOCKET = connfd } 
connfd := accept(serversock, @cliaddr, @len); 
recv(connfd, inLen, sizeof(inLen), 0); 
//up to here everything is fine with the strem: 
//Size = InLen, Position = 0, all bytes are '0' 
rec := recv(connfd, inBuf, inLen, 0); 
//rec = inLen, which is fine 
//now this: inBuf: FMemory $1, FSize 9 (no matter how long the msg is) 
// FPosition 7077987 and FBytes: many many random 
DebugOutput(inBuf.DataString); //the error is thrown here 

gdzie connfd ma gniazdo połączone, servsock jest gniazdem słuchu, inLen jest Cardinal zawierający długość inBuf, inBuf jest globalnym TStringStream. rec jest kardynalnym, zawierającym # bajtów odebranych przez recv.

{ the client's send function } 
function SSend(sock :TSocket; addr :sockaddr_in; msg :TStringStream) :Integer; 
var 
    len: Cardinal; 
begin 
    len := msg.Size; 

    send(sock, len, sizeof(len), 0); 
    msg.Seek(0,0); 
    send(sock, msg, sizeof(msg), 0); 

    Result := 0; 
end; 

i wezwać klienta do SSend:

{ CREATE (OUTPUT)STREAM } 
s := TStringStream.Create; 
    s.WriteString(_input.Text); 
    //_input is a TMemo with text, let's say, ´hello´ 
SSend(client, servaddr, s); 
//client is a TSocket 

Dzięki za wszelką pomoc z góry!
p1.e

+0

Dlaczego nie wybrałeś Delphi DataSnap, jeśli tworzysz prostą aplikację klient/serwer? – Peter

+0

Używam winsock, ponieważ muszę pokazać, jak działają gniazda. –

+0

Używanie biblioteki wyższego poziomu, takiej jak Indy lub Synapse, ułatwi Ci życie i pozwoli zaoszczędzić czas :) – mjn

Odpowiedz

7

są przechodzącą w recv wskaźnik do samego TStringStream obiektu, a nie do jego bufora danych. Właśnie dlatego obiekt zostaje uszkodzony. Użyj właściwości Memory: recv(connfd, inBuf.Memory^, inLen, 0).

To samo dotyczy wysyłania: wysyła dane ze strumienia, a nie obiekt strumienia (sizeof(msg) w swoim SSend zwraca tylko rozmiar wskaźnika).

+0

Linia 'recv (connfd, inBuf.Memory, inLen, 0);' daje błąd kompilacji: in.Buf jest wyrażeniem stałym, natomiast var jest wymagany –

+0

Przepraszamy, to powinno być 'inBuf.Memory ^' (prawdziwy "var" to obszar pamięci wskazywany przez 'Memory'). Poprawiłem to w odpowiedzi. – Inspired

+0

Tak, właśnie to wymyśliłem :) zmieniono linie na 'rec: = recv (connfd, inBuf.Memory ^, inLen, 0);' i 'send (skarpeta, msg.Memory ^, msg.Size, 0); 'Dzięki za pomoc! –