5

I'm working on a fairly simple Client/Server application and have some trouble receiving a TStringStream from a client using recv provided by winsock API.
I keep getting this error: 'access violation at 0x00000000: read of address 0x00000000'.
The client only copies text into a TStringStream, gets it's length and sends it to the server. The server then receives the Stream and outputs it's text. Below some abstract code extracts.

{ 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

where connfd is the connected socket, servsock is the listening socket, inLen is a cardinal containing the length of inBuf, inBuf is a global TStringStream. rec is a cardinal containing the # of bytes received by 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;

and the client's call to 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

Thanks for any help in advance!
p1.e

p1.e
  • 497
  • 1
  • 4
  • 5
  • Why didn't you go for Delphi DataSnap if you're making a simple client/server application? – Peter May 25 '13 at 12:13
  • I'm using winsock, because I need to demonstrate how sockets work. – p1.e May 25 '13 at 12:19
  • Using a higher level library like Indy or Synapse will make your life easier and can save time :) – mjn May 25 '13 at 13:24
  • 2
    I normally do :) but, for school I need to show how sockets operate. I therefore use the basic winsock routines. – p1.e May 25 '13 at 13:33

1 Answers1

7

You are passing into recv a pointer to TStringStream object itself, not to its data buffer. That's why the object gets corrupted. Use Memory property: recv(connfd, inBuf.Memory^, inLen, 0).

The same goes for sending: send data from stream, not the stream object (sizeof(msg) in your SSend returns just size of a pointer).

nullptr
  • 11,008
  • 1
  • 23
  • 18
  • The line `recv(connfd, inBuf.Memory, inLen, 0);` gives a compile error: in.Buf is a constant expression, while a var is required – p1.e May 25 '13 at 12:17
  • Sorry, it should be `inBuf.Memory^` (the real "var" is a memory area pointed to by `Memory`). I've corrected this in the answer. – nullptr May 25 '13 at 12:35
  • Yes, I just figured that out, too :) changed the lines to `rec := recv(connfd, inBuf.Memory^, inLen, 0);` and `send(sock, msg.Memory^, msg.Size, 0);` Thanks for help! – p1.e May 25 '13 at 12:38
  • Will the capacity of the TStringStream object not need to be set up first to prevent UB? – Martin James May 28 '13 at 14:14
  • Yes, it surely will. I suppose the code is just omitted, but the capacity is set correctly (there is a comment `Size = InLen` before `recv`). – nullptr May 28 '13 at 14:24