【问题标题】:TStringStream gets corrupted when received using (winsock's) recv?使用(winsock 的)recv 接收到 TStringStream 时会损坏?
【发布时间】:2013-05-20 21:31:41
【问题描述】:

我正在开发一个相当简单的客户端/服务器应用程序,但在使用 winsock API 提供的 recv 从客户端接收 TStringStream 时遇到了一些问题。
我不断收到此错误:“0x00000000 处的访问冲突:读取地址 0x00000000”。
客户端只将文本复制到 TStringStream 中,获取它的长度并将其发送到服务器。然后服务器接收 Stream 并输出它的文本。 下面是一些抽象代码摘录。

{ 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

其中connfd是连接的socket,servsock是监听的socket,inLen是一个包含inBuf长度的基数,inBuf是一个全局的TStringStream。 rec 是一个基数,包含 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;

以及客户端对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

提前感谢您的帮助!
p1.e

【问题讨论】:

  • 如果您正在制作一个简单的客户端/服务器应用程序,为什么不选择 Delphi DataSnap?
  • 我使用的是winsock,因为我需要演示套接字是如何工作的。
  • 使用 Indy 或 Synapse 等更高级别的库将使您的生活更轻松,并且可以节省时间:)
  • 我通常这样做:) 但是,对于学校,我需要展示套接字是如何工作的。因此,我使用基本的 winsock 例程。

标签: delphi stream winsock recv


【解决方案1】:

您正在向recv 传递一个指向TStringStream 对象本身的指针,而不是它的数据缓冲区。这就是对象被破坏的原因。使用Memory 属性:recv(connfd, inBuf.Memory^, inLen, 0)

发送也是如此:从流发送数据,而不是流对象(SSend 中的sizeof(msg) 只返回指针的大小)。

【讨论】:

  • recv(connfd, inBuf.Memory, inLen, 0); 行给出编译错误:in.Buf 是常量表达式,而 var 是必需的
  • 对不起,应该是inBuf.Memory^(真正的“var”是Memory指向的内存区域)。我已经在答案中更正了这一点。
  • 是的,我也想通了 :) 将这些行更改为 rec := recv(connfd, inBuf.Memory^, inLen, 0);send(sock, msg.Memory^, msg.Size, 0); 感谢您的帮助!
  • 会不会不用先设置TStringStream对象的容量来防止UB?
  • 是的,肯定会的。我想代码只是省略了,但是容量设置正确(recv之前有注释Size = InLen)。
猜你喜欢
  • 1970-01-01
  • 2012-07-05
  • 2015-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-31
  • 1970-01-01
  • 2021-11-19
相关资源
最近更新 更多