Z
zheng
Unregistered / Unconfirmed
GUEST, unregistred user!
请看以下代码:(非阻赛模式,问题出在传送超大量数据连续触发Read时间,在取数据叠加时,出现怪问题,每触发一次数据总量不但没有增加,反而减少了)
服务端:
Procedure SendScreen(aStream: TMemoryStream); //aStream很大,大概有64K大小。
var Count, Remain: Integer;
Buffer: PChar;
begin
Count := aStream.Size;
GetMem(Buffer, Count + 1);
try
aStream.ReadBuffer(Buffer^, Count);
Remain := Count;
repeat
if Remain > MaxBufSize then //MaxBufSize=4096
if Send(CliSocket, Buffer[Count-Remain], MaxBufSize, 0) = SOCKET_ERROR then Continue
else
if Send(CliSocket, Buffer[Count-Remain], Remain, 0) = SOCKET_ERROR then Continue;
Remain := Remain - MaxBufSize;
until Remain <= 0;
finally
aStream.Clear;
FreeMem(Buffer);
end;
end;
注:原先我是用设置“SetSockOpt(SrvSocket, SOL_SOCKET, SO_SNDBUF, @BufSize, Sizeof(Integer))”(BufSize=64K)
然后一次性发送,但出现上述问题;我以为是一次发送数据量太大的原因,因此改成上面的分次发送,谁知问题依然存在!
付套接字设置(客户端也一样):
SrvSocket := Socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
SrvAddr.SIn_Family := AF_INET;
SrvAddr.SIn_Port := htons(TCP_PORT);
SrvAddr.SIn_Addr.S_Addr := INADDR_ANY;
Bind(SrvSocket, @SrvAddr, Sizeof(SrvAddr));
Listen(SrvSocket, 5);
WSAAsyncSelect(SrvSocket, Handle, WM_SOCK, FD_READ or FD_ACCEPT or FD_CLOSE);
客户端:
procedure TForm1.RecvData(var Message: TMessage); {message WM_SOCK}
var Event: Word;
begin
Event := WSAGetSelectEvent(Message.LParam);
case Event of
FD_CONNECT:
begin
HasConnected := True;
end;
FD_READ:
ReadData(); //*************接收数据****************//
FD_CLOSE:
begin
HasConnected := False;
Messagebox(0, 'Server Closed!', AppName, + MB_ICONINFORMATION + MB_OK);
end;
end;
end;
procedure TForm1.ReadData; //FBuffer: PChar;
var Buf: array [0..MaxBufSize-1] of Char;
Len: Integer;
begin
Buf := '';
Len := Recv(FCliSocket, Buf, MaxBufSize, 0); //******* Recv() Socket ********//
//Buf[Len] := #0;
if Command = 'SDSR' then //假如收到“SDSR”标记,则说明已经接收完所有发送的数据。
begin
FZipSize := StrToInt(Copy(Buf, CommandBit + 1, DataLenBit)); //这些字符串都能够正确取得,不要怀疑这里出错。
Messagebox(0, PChar(IntToStr(FZipSize)), AppName, + MB_ICONINFORMATION + MB_OK);
FRcvLen := Len;
GetMem(FBuffer, FZipSize);
FBuffer := Buf;
end else //没有收到“SDSR”标记,则说明正在接收发送的数据。
begin
FRcvLen := FRcvLen + Len;
Messagebox(0, PChar(IntToStr(FRcvLen)), AppName, + MB_ICONINFORMATION + MB_OK); //问题1:FRcvLen值越来越小,每次触发就减少一些,好象是没有规律地减少。
//if FRcvLen > FZipSize then raise Exception.Create();
StrCat(FBuffer, Buf); //将PChar:Buf添加到PChar:FBuffer中
Messagebox(0, PChar(IntToStr(StrLen(FBuffer))), AppName, + MB_ICONINFORMATION + MB_OK); //问题2:FBuffer内容也不断减少。
if FRcvLen = FZipSize then //接收完毕
begin
try
Dosomething; //***************//
finally
FZipSize := 0;
FRcvLen := 0;
FreeMem(FBuffer);
end;
end;
end;
end;
我已经搞了很多天都搞不定,试了很多方法都不行,我猜肯定是对非阻塞模式的原理不了解造成,请务必为我清楚解释一下。最好附上几行关键代码。
服务端:
Procedure SendScreen(aStream: TMemoryStream); //aStream很大,大概有64K大小。
var Count, Remain: Integer;
Buffer: PChar;
begin
Count := aStream.Size;
GetMem(Buffer, Count + 1);
try
aStream.ReadBuffer(Buffer^, Count);
Remain := Count;
repeat
if Remain > MaxBufSize then //MaxBufSize=4096
if Send(CliSocket, Buffer[Count-Remain], MaxBufSize, 0) = SOCKET_ERROR then Continue
else
if Send(CliSocket, Buffer[Count-Remain], Remain, 0) = SOCKET_ERROR then Continue;
Remain := Remain - MaxBufSize;
until Remain <= 0;
finally
aStream.Clear;
FreeMem(Buffer);
end;
end;
注:原先我是用设置“SetSockOpt(SrvSocket, SOL_SOCKET, SO_SNDBUF, @BufSize, Sizeof(Integer))”(BufSize=64K)
然后一次性发送,但出现上述问题;我以为是一次发送数据量太大的原因,因此改成上面的分次发送,谁知问题依然存在!
付套接字设置(客户端也一样):
SrvSocket := Socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
SrvAddr.SIn_Family := AF_INET;
SrvAddr.SIn_Port := htons(TCP_PORT);
SrvAddr.SIn_Addr.S_Addr := INADDR_ANY;
Bind(SrvSocket, @SrvAddr, Sizeof(SrvAddr));
Listen(SrvSocket, 5);
WSAAsyncSelect(SrvSocket, Handle, WM_SOCK, FD_READ or FD_ACCEPT or FD_CLOSE);
客户端:
procedure TForm1.RecvData(var Message: TMessage); {message WM_SOCK}
var Event: Word;
begin
Event := WSAGetSelectEvent(Message.LParam);
case Event of
FD_CONNECT:
begin
HasConnected := True;
end;
FD_READ:
ReadData(); //*************接收数据****************//
FD_CLOSE:
begin
HasConnected := False;
Messagebox(0, 'Server Closed!', AppName, + MB_ICONINFORMATION + MB_OK);
end;
end;
end;
procedure TForm1.ReadData; //FBuffer: PChar;
var Buf: array [0..MaxBufSize-1] of Char;
Len: Integer;
begin
Buf := '';
Len := Recv(FCliSocket, Buf, MaxBufSize, 0); //******* Recv() Socket ********//
//Buf[Len] := #0;
if Command = 'SDSR' then //假如收到“SDSR”标记,则说明已经接收完所有发送的数据。
begin
FZipSize := StrToInt(Copy(Buf, CommandBit + 1, DataLenBit)); //这些字符串都能够正确取得,不要怀疑这里出错。
Messagebox(0, PChar(IntToStr(FZipSize)), AppName, + MB_ICONINFORMATION + MB_OK);
FRcvLen := Len;
GetMem(FBuffer, FZipSize);
FBuffer := Buf;
end else //没有收到“SDSR”标记,则说明正在接收发送的数据。
begin
FRcvLen := FRcvLen + Len;
Messagebox(0, PChar(IntToStr(FRcvLen)), AppName, + MB_ICONINFORMATION + MB_OK); //问题1:FRcvLen值越来越小,每次触发就减少一些,好象是没有规律地减少。
//if FRcvLen > FZipSize then raise Exception.Create();
StrCat(FBuffer, Buf); //将PChar:Buf添加到PChar:FBuffer中
Messagebox(0, PChar(IntToStr(StrLen(FBuffer))), AppName, + MB_ICONINFORMATION + MB_OK); //问题2:FBuffer内容也不断减少。
if FRcvLen = FZipSize then //接收完毕
begin
try
Dosomething; //***************//
finally
FZipSize := 0;
FRcvLen := 0;
FreeMem(FBuffer);
end;
end;
end;
end;
我已经搞了很多天都搞不定,试了很多方法都不行,我猜肯定是对非阻塞模式的原理不了解造成,请务必为我清楚解释一下。最好附上几行关键代码。