unit uStreamCoderSocket;
interface
uses
uICoderSocket, Classes, SysUtils, uZipTools;
type
{$if CompilerVersion < 18}
TBytes = array of Byte;
{$IFEND}
TStreamCoderSocket = class(TObject)
private
class function SendStream(pvSocket: ICoderSocket; pvStream: TStream): Integer;
public
///
/// 接收解码
///
/// Boolean
///
/// (TClientSocket)
/// (TObject)
class function RecvObject(pvSocket: ICoderSocket; pvObject: TObject): Boolean;
///
/// 编码发送
///
/// (TClientSocket)
/// (TObject)
class function SendObject(pvSocket: ICoderSocket; pvObject: TObject): Integer;
end;
implementation
//PACK_FLAG + CRC_VALUE + STREAM_LEN + STREAM_DATA
uses
uByteTools;
const
PACK_FLAG = $D10;
MAX_OBJECT_SIZE = 1024 * 1024 * 10; //最大对象大小 10M , 大于10M 则会认为错误的包。
const
BUF_BLOCK_SIZE = 1024 * 8;
resourcestring
strRecvException_ErrorFlag = '错误的包头数据,断开与服务器的连接';
strRecvException_ErrorData = '错误的数据,断开与服务器的连接';
strRecvException_VerifyErr = '错误的数据包,校验失败!';
strSendException_TooBig = '数据包太大,请在业务层分拆发送,最大数据包[%d]!';
strSendException_NotEqual = '发送Buffer错误指定发送%d,实际发送:%d';
{ TStreamCoderSocket }
class function TStreamCoderSocket.RecvObject(pvSocket: ICoderSocket;
pvObject: TObject): Boolean;
var
lvBytes:TBytes;
lvReadL, lvTempL:Integer;
lvPACK_FLAG:Word;
lvDataLen: Integer;
lvVerifyValue, lvVerifyDataValue:Cardinal;
lvPByte:PByte;
begin
pvSocket.recvBuf(@lvPACK_FLAG, 2);
if lvPACK_FLAG <> PACK_FLAG then
begin
pvSocket.closeSocket;
//错误的包数据
raise Exception.Create(strRecvException_ErrorFlag);
end;
//veri value
pvSocket.recvBuf(@lvVerifyValue, SizeOf(lvVerifyValue));
//headlen
pvSocket.recvBuf(@lvReadL, SizeOf(lvReadL));
lvDataLen := TByteTools.swap32(lvReadL);
//文件头不能过大
if lvDataLen > MAX_OBJECT_SIZE then
begin
//错误的包数据
pvSocket.closeSocket;
//错误的包数据
raise Exception.Create(strRecvException_ErrorData);
end;
SetLength(lvBytes,lvDataLen);
lvPByte := PByte(@lvBytes[0]);
lvReadL := 0;
while lvReadL < lvDataLen do
begin
lvTempL := pvSocket.recvBuf(lvPByte, lvDataLen - lvReadL);
if lvTempL = -1 then
begin
RaiseLastOSError;
end;
Inc(lvPByte, lvTempL);
lvReadL := lvReadL + lvTempL;
end;
lvVerifyDataValue := TZipTools.verifyData(lvBytes[0], lvDataLen);
if lvVerifyDataValue <> lvVerifyValue then
begin
raise Exception.Create(strRecvException_VerifyErr);
end;
TStream(pvObject).Write(lvBytes[0], lvDataLen);
Result := true;
end;
class function TStreamCoderSocket.SendObject(pvSocket: ICoderSocket; pvObject:
TObject): Integer;
var
lvPACK_FLAG: WORD;
lvDataLen, lvWriteIntValue: Integer;
lvBuf: TBytes;
lvStream:TMemoryStream;
lvVerifyValue:Cardinal;
begin
lvPACK_FLAG := PACK_FLAG;
lvStream := TMemoryStream.Create;
try
TStream(pvObject).Position := 0;
if TStream(pvObject).Size > MAX_OBJECT_SIZE then
begin
raise Exception.CreateFmt(strSendException_TooBig, [MAX_OBJECT_SIZE]);
end;
//pack_flag
lvStream.Write(lvPACK_FLAG, 2);
//
lvDataLen := TStream(pvObject).Size;
// stream data
SetLength(lvBuf, lvDataLen);
TStream(pvObject).Read(lvBuf[0], lvDataLen);
//veri value
lvVerifyValue := TZipTools.verifyData(lvBuf[0], lvDataLen);
lvStream.Write(lvVerifyValue, SizeOf(lvVerifyValue));
lvWriteIntValue := TByteTools.swap32(lvDataLen);
// stream len
lvStream.Write(lvWriteIntValue, SizeOf(lvWriteIntValue));
// send pack
lvStream.write(lvBuf[0], lvDataLen);
Result := SendStream(pvSocket, lvStream);
finally
lvStream.Free;
end;
end;
class function TStreamCoderSocket.SendStream(pvSocket: ICoderSocket; pvStream:
TStream): Integer;
var
lvBufBytes:array[0..BUF_BLOCK_SIZE-1] of byte;
l, j, r, lvTotal:Integer;
P:PByte;
begin
Result := 0;
if pvStream = nil then Exit;
if pvStream.Size = 0 then Exit;
lvTotal :=0;
pvStream.Position := 0;
repeat
//FillMemory(@lvBufBytes[0], SizeOf(lvBufBytes), 0);
l := pvStream.Read(lvBufBytes[0], SizeOf(lvBufBytes));
if (l > 0) then
begin
P := PByte(@lvBufBytes[0]);
j := l;
while j > 0 do
begin
r := pvSocket.sendBuf(P, j);
if r = -1 then
begin
RaiseLastOSError;
end;
Inc(P, r);
Dec(j, r);
end;
lvTotal := lvTotal + l;
end else Break;
until (l = 0);
Result := lvTotal;
end;
end.