[置顶] DELPHI高性能大容量SOCKET并发(六):协议字符集

UTF-8

UTF-8是UNICODE的一种变长字符编码又称万国码,由Ken Thompson于1992年创建。现在已经标准化为RFC 3629。UTF-8用1到6个字节编码UNICODE字符。用在网页上可以同一页面显示中文简体繁体及其它语言(如日文,韩文)。

使用UTF-8的好处是现在一些手机平台都是使用UTF-8,另外在一些嵌入式平台,如果不支持中文,只支持英文,可以不转换,UTF-8就可以识别。

DELPHI默认支持的编码是ANSI,为了支持UTF-8,需要转换下,为了编程简便性,我们只在发包和解包的地方进行UTF-8转换。

发包:

function TBaseClientSocket.ControlCommand(const ACommand: string;
  ARequest, AResponse: TStrings; const AData: string): Boolean;
var
  slBuff: TStringList;
  dwPacketLen, dwCommandLen, dwCode: Cardinal;
  sBuff: string;
  utf8Command, utf8Data: UTF8String;
begin
  try
    slBuff := TStringList.Create;
    try
      FClient.ReadTimeout := FTimeOutMS;
      FClient.MaxLineLength := 1024 * 1024 * 1024;
      slBuff.Add('[' + CSRequest + ']');
      slBuff.Add(CSCommand + CSEqualSign + ACommand);
      if Assigned(ARequest) then
        slBuff.AddStrings(ARequest);
      sBuff := slBuff.Text;
      utf8Command := AnsiToUtf8(sBuff); //把ANSI转为UTF-8
      if not IsEmptyStr(AData) then
        utf8Data := AnsiToUtf8(AData); //把ANSI转为UTF-8
      dwPacketLen := SizeOf(Cardinal) + Length(utf8Command) + Length(utf8Data); //总长度
      dwCommandLen := Length(utf8Command); //命令长度
      FClient.WriteCardinal(dwPacketLen, False); //发送整个包长度
      FClient.WriteCardinal(dwCommandLen, False); //发送命令长度
      FClient.WriteBuffer(PUTF8String(utf8Command)^, dwCommandLen, True); //发送命令内容
      if not IsEmptyStr(AData) then
        FClient.WriteBuffer(PUTF8String(utf8Data)^, Length(utf8Data), True); //发送数据
      dwPacketLen := FClient.ReadCardinal(False); //读取整个包的长度
      dwCommandLen := FClient.ReadCardinal(False); //读取命令长度
      SetLength(utf8Command, dwPacketLen - SizeOf(Integer));
      FClient.ReadBuffer(PUTF8String(utf8Command)^, dwPacketLen - SizeOf(Integer)); //读取后续内容
      slBuff.Clear;
      slBuff.Text := Utf8ToAnsi(utf8Command); //转换为ANSI
      dwCode := Cardinal(StrToInt(slBuff.Values[CSCode]));
      Result := dwCode = 0;
      if not Result then
        FLastError := GetErrorCodeString(dwCode) + ': ' + slBuff.Values[CSMessage];
      if Assigned(AResponse) then
        AResponse.Text := slBuff.Text;
    finally
      slBuff.Free;
    end;
  except
    on E: Exception do
    begin
      FLastError := E.Message;
      Result := False;
    end;
  end;
end;
解包:

function TBaseSocket.DecodePacket(APacketData: PByte;
  const ALen: Integer): Boolean;
var
  CommandLen: Integer;
  UTF8Command: UTF8String;
begin
  if ALen > 4 then //命令长度为4字节,因而长度必须大于4
  begin
    CopyMemory(@CommandLen, APacketData, SizeOf(Cardinal)); //获取命令长度
    Inc(APacketData, SizeOf(Cardinal));
    SetLength(UTF8Command, CommandLen);
    CopyMemory(PUTF8String(UTF8Command), APacketData, CommandLen); //读取命令
    Inc(APacketData, CommandLen);
    FRequestData := APacketData; //数据
    FRequestDataLen := ALen - SizeOf(Cardinal) - CommandLen; //数据长度
    FRequest.Text := Utf8ToAnsi(UTF8Command); //把UTF8转为Ansi
    Result := True;
  end
  else
    Result := False; 
end;

这样好处就是外部编程接口就都是ANSI,和DELPHI保持一致,应用编写就可以不用注意这个细节。

V1版下载地址:http://download.csdn.net/detail/sqldebug_fan/4510076,需要资源10分,有稳定性问题,可以作为研究稳定性用;

V2版下载地址:http://download.csdn.net/detail/sqldebug_fan/5560185,不需要资源分,解决了稳定性问题和提高性能;免责声明:此代码只是为了演示IOCP编程,仅用于学习和研究,切勿用于商业用途。水平有限,错误在所难免,欢迎指正和指导。邮箱地址:[email protected]

你可能感兴趣的:([置顶] DELPHI高性能大容量SOCKET并发(六):协议字符集)