通讯协议:UDP
通讯架构:车----->服务器---->客户中心
【汽车】向【服务器】发数据,【服务器】收到数据后处理,在发送给【客户中心】
1、有2万辆汽车,每辆平均一分钟向服务气发送四条数据,也就是说服务一分钟内收到8万条数据。
2、服务器处理一条数据的平均时间,大约10毫秒,也就是说一分大约处理6000条数据(包括处理完后发送给【客户中心】)。
3、引发问题:由如服务器处理速度慢于接收速度,就引发大量数据丢失。
4、我的解决方案是:服务器收到数据后,不进行处理,把数据放到一个数据缓冲区里面(这样可以保证数据不被丢失),在采取多线程处理数据,设想如果一个线程一分钟能处理六千条,四个处理线程就可以搞定,但是发现多个线程处理,在单CPU的情况比一个线程处理好像还好慢,个人估计是由如线程之间同学协调,和线程切换引起。这样就引起另一个情况,由如处理速度,没有提升上来,数据缓冲区将不断增加,最后引起内存不够,而死掉。
对以上情况现在求解决方案:
解决方案前提:不加增加服务器数量(服务器是IBM的专用服务器)。
解决后重谢!如果有兴趣可以加本人QQ讨论也可以,QQ:63731429。

解决方案 »

  1.   

    换服务器吧,估计一个线程CPU就90%了,100个线程也没有用的
      

  2.   

    CPU的利用率才40%,不用换服务器
      

  3.   

    先分析清楚你的线程每个处理步骤消耗的时间:计算时间、数据库/文件等IO时间、数据发送等;
    多线程提高效率的方式是由多个线程对各种资源(计算资源CPU、网络资源、硬盘IO资源、数据库等)进行时分复用,而线程并发度受速度最慢的资源的上限限制,假如你的数据库并发IO速度最大1万条数据/分,那么服务器撑死也只能处理到1万条/分
      

  4.   

    谢谢!bomdy,我对每个步分析后,有不懂的在向你请教
      

  5.   

    >>发现多个线程处理,在单CPU的情况比一个线程处理好像还好慢  在"处理线程"中创建一个线程单独使用队列,不要与其它的“处理线程”有共享锁的冲突,这样看看处理会不会好些?
      线程间使用互斥,昨界之间的,速度真是会慢下来,再加上处理没写好的话。  或者说你将那需要10ms的处理发上来看看。
      

  6.   

    还有最好自己写个队列,不要使用TList之间的东西。
    写个FIFO的东西,应该很简单,只要注意些内存缓冲,效率会快好多。
      

  7.   

    车到服务器之间是否可以双向通讯?如果可以的话,服务器可以回复一个Ack作为应答,车收到后释放指令,如果没有收到Ack就在下次重发。使用UDP协议,UDP本身不保证数据都能到达,这个是网络设备的问题,不只是服务器的问题
      

  8.   

    使用UDP、线程池之类的东西,用Indy10测试一下吧。
      

  9.   

    我不喜欢 Indy10 的纤程
    indy 做 server 不好1、有2万辆汽车,每辆平均一分钟向服务气发送四条数据,也就是说服务一分钟内收到8万条数据。
    这个 似乎 不难  我今天 晚上 写写demo 看看
      

  10.   

    withcsharp()  谢谢你我等你的消息。还有一个问题没有说明,数据处理(包括数据入数据库)
      

  11.   

    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, WSocket, ExtCtrls, Grids, StdCtrls;
    const
      BlockSize = 32;
    type
      TtestThread = class(TThread)
      private
        idx: Integer;
        Fid: integer;
        FsentCount: Integer;
        FbeginTime: DWORD;
        buff: array[0..BlockSize - 1] of Char;
        WSocket: TWSocket;
        procedure makeBuff;
        procedure WriteIdx;
      protected
        procedure Execute; override;
      public
        constructor Create(Id: Integer);
        destructor Destroy; override;    property sentCount: integer read FsentCount;
        property beginTime: DWORD read FbeginTime;
      end;
      TForm1 = class(TForm)
        Panel1: TPanel;
        Panel2: TPanel;
        StringGrid1: TStringGrid;
        Timer1: TTimer;
        Button1: TButton;
        Label1: TLabel;
        Label2: TLabel;
        Label3: TLabel;
        Label4: TLabel;
        procedure FormCreate(Sender: TObject);
        procedure Button1Click(Sender: TObject);
        procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
        procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
          Rect: TRect; State: TGridDrawState);
        procedure Timer1Timer(Sender: TObject);
      private
        FbeginTime: DWORD;
        testlist: array of TtestThread;
        procedure cleartestList;
        procedure addTest(count: integer);
      public  end;var
      Form1: TForm1;implementation{$R *.dfm}procedure TForm1.addTest(count: integer);
    var
      i: integer;
    begin
      cleartestList;
      SetLength(testlist, count);
      for i := low(testlist) to high(testlist) do
        testlist[i] := TtestThread.Create(i);  StringGrid1.RowCount := count + 1;
    end;procedure TForm1.cleartestList;
    var
      i: integer;
    begin
      for i := low(testlist) to high(testlist) do
        testlist[i].Terminate;
      for i := low(testlist) to high(testlist) do
        testlist[i].WaitFor;  for i := low(testlist) to high(testlist) do
        testlist[i].Free;  SetLength(testlist, 0);
    end;procedure TForm1.FormCreate(Sender: TObject);
    begin
      StringGrid1.DoubleBuffered := true;
      StringGrid1.Cells[0, 0] := '序号';
      StringGrid1.Cells[1, 0] := '发送包数';
      StringGrid1.Cells[2, 0] := '发送包数/秒';
      FbeginTime := GetTickCount;
      addTest(30);
    end;{ TtestThread }constructor TtestThread.Create(Id: Integer);
    begin
      idx := 0;
      FsentCount := 0;
      Fid := Id;
      makeBuff;
      FbeginTime := GetTickCount;
      WSocket := nil;
      FreeOnTerminate := false;
      inherited Create(False);end;destructor TtestThread.Destroy;
    begin
      if WSocket <> nil then
        WSocket.Free;
      inherited;
    end;procedure TtestThread.Execute;
    var
      i: integer;
    begin
      WSocket := TWSocket.Create(nil);  while not Terminated do
        begin
          try
            for i := 1 to 10 do
              begin
                Sleep(10);
                if Terminated then
                  Break;
              end;
            if Terminated then
              Break;        WSocket.Proto := 'udp';
            WSocket.Addr := '127.0.0.1';
            WSocket.Port := '1001';
            WSocket.LocalPort := IntToStr(2000 + fId); WSocket.Connect;
            for i := 1 to 20 do
              begin            inc(idx);
                WriteIdx;            WSocket.Send(@(buff[0]), BlockSize);            inc(FsentCount)
              end;
            WSocket.Close;
          except
          end;
        end;
    end;procedure TtestThread.makeBuff;
    var
      s: string;
    begin
      FillChar(buff[0], BlockSize, 0);
      buff[0] := #02;
      buff[BlockSize - 1] := #03;
      Move(fid, buff[1], 4);
      Move(idx, buff[5], 4);
      s := '我爱啃猪脚 我爱啃猪脚';
      Move(s[1], buff[9], length(s));
    end;procedure TtestThread.WriteIdx;
    begin
      Move(idx, buff[5], 4);
    end;procedure TForm1.Button1Click(Sender: TObject);
    begin
      close;
    end;procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    begin
      Timer1.Enabled := false;
      cleartestList;
    end;procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    var
      idx: Integer;
      bcolor, fcolor: TColor;
      s: string;
    begin
      if gdSelected in State then
        begin
          bcolor := clHighlight;
          fcolor := clHighlightText
        end
      else
        if gdFixed in State then
          begin
            bcolor := clBtnFace;
            fcolor := clWindowText;
          end
        else
          begin
            bcolor := clWhite;
            fcolor := clWindowText;
          end;
      with StringGrid1 do
        begin
          Canvas.Brush.Color := bcolor;
          Canvas.Font.Color := fcolor;
          Canvas.FillRect(Rect);
          if ARow = 0 then
            s := Cells[acol, arow]
          else
            begin
              case ACol of
                0: s := IntToStr(ARow);
                1, 2:
                  begin
                    idx := ARow - 1;                if idx > high(testlist) then
                      begin
                        s := '';
                      end
                    else
                      begin
                        if ACol = 1 then
                          s := IntToStr(testlist[idx].sentCount)
                        else
                          begin
                            s := FormatFloat('0.000', testlist[idx].sentCount * 1000 / (10 + gettickcount - testlist[idx].begintime));
                          end;
                      end;
                  end;
              end;
            end;
          DrawText(Canvas.Handle, pchar(s), -1, Rect, DT_CENTER or DT_SINGLELINE or DT_VCENTER);
        end;end;procedure TForm1.Timer1Timer(Sender: TObject);
    var
      i, c: integer;begin
      Timer1.Enabled := false;
      StringGrid1.Repaint;
      c := 0;
      for i := low(testlist) to high(testlist) do
        inc(c, testlist[i].sentCount);
      Label2.Caption := IntToStr(c);
      Label4.Caption := FormatFloat('0.000', c * 1000 / (10 + gettickcount - Fbegintime));
      Timer1.Enabled := true;
    end;end.
      

  12.   

    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, WSocket, ExtCtrls, WinSock, StdCtrls;
    const
      BuffSize = 1024 * 512;
      BlockSize = 32;
    type
      TForm1 = class(TForm)
        WSocket: TWSocket;
        Label1: TLabel;
        Label2: TLabel;
        Label3: TLabel;
        Label4: TLabel;
        Timer1: TTimer;
        Label5: TLabel;
        Label6: TLabel;
        Label7: TLabel;
        Label8: TLabel;
        procedure FormCreate(Sender: TObject);
        procedure WSocketDataAvailable(Sender: TObject; Error: Word);
        procedure Timer1Timer(Sender: TObject);
      private
        buff_Idx: integer;
        buff: array[0..BuffSize] of Byte;
        ReceiveCount: Integer;
        ErrCount: Integer;
        LastTime: DWORD;
        LastReceiveCount: Integer;
        procedure saveFile;
      public  end;var
      Form1: TForm1;
      path: string;
    implementation{$R *.dfm}procedure TForm1.FormCreate(Sender: TObject);
    begin
      ReceiveCount := 0;
      ErrCount := 0;
      buff_Idx := 0;
      LastTime := 0;
      LastReceiveCount := 0;
      WSocket.Listen;
    end;procedure TForm1.saveFile;
    var
      fn: string;
      fs: TFileStream;
    begin
      fn := path + IntToStr(GetTickCount) + '.dat';
      fs := TFileStream.Create(fn, fmcreate);
      fs.WriteBuffer(buff, buff_Idx + 1);
      FreeAndNil(fs);
      buff_Idx := 0;
    end;procedure TForm1.WSocketDataAvailable(Sender: TObject; Error: Word);
    var
      Len: Integer;
      Src: TSockAddrIn;
      SrcLen: Integer;
    begin
      if buff_Idx > BuffSize - BlockSize then
        saveFile;
      inc(ReceiveCount);
      SrcLen := SizeOf(Src);
      Len := WSocket.ReceiveFrom(@(buff[buff_Idx]), BlockSize, Src, SrcLen);  if Len < 0 then
        exit;  if Len <> BlockSize then
        begin
          Inc(ErrCount);
        end
      else
        begin
          inc(buff_Idx, BlockSize);
          if buff[buff_Idx - 1] <> 3 then
            Inc(ErrCount);
        end;
    end;procedure TForm1.Timer1Timer(Sender: TObject);
    var
      t: DWORD;
      i: integer;
    begin
      Label3.Caption := IntToStr(ReceiveCount);
      Label4.Caption := IntToStr(errCount);
      t := GetTickCount;
      if LastTime > 0 then
        begin
          i := ReceiveCount - LastReceiveCount;
          Label8.Caption := IntToStr(i);
          Label7.Caption := IntToStr(i * 60);
        end;
      LastTime := t;
      LastReceiveCount := ReceiveCount;end;initialization
      path := ExtractFilePath(path);end.
      

  13.   

    我试了 每分钟 大约 30万 到 50 万 的 条数据
    我是转存成 文件了 
    数据入库 可以 交给 另外的 程序 处理  可以不用文件 用共享内存。所以 服务一分钟内收到8万条数据 根本不难
    现在 的 问题 实际上 是 数据库 快速 数据插入
    了 你用 sql 一条数据一条数据 的插入 那是 肯定 不行的
    你可以 直接 用 bcp ,BULK INSERT  
    或者 直接引用sql的dll可以看 sql server 提供 的 c代码
      

  14.   

    嗯,同意。
    最后还是先写到文件,再每晚定时insert到数据库,能不与DB交互就尽量不交互,或延后处理。
      

  15.   

    楼主是不是做gps方面的东东我想这种问题 应该主要看处理数据上能否优化,尽量减少处理数据占用的时间,比如如果要每天记录都写数据库 ,可以参考大家的意见,用 bcp ,BULK INSERT  或者 直接引用sql的dll什么的。然后就是开线程,可以把占用时间长的操作 单独用线程处理。
      

  16.   

    楼主可以这样:
    1.单独做线程,只接收数据,统计接收速度,把数据保存文件。
    2.单独做线程,从文件中读取数据,分析,发送,统计处理速度。如果2速度<=1速度,则不需要考虑多线程,因为会更慢(对于单CPU),只能改进硬件或改进分析方法或发送方法另2速度大幅提高。
    如果2速度>1速度,还要看大多少,大一点点可能会造成接收数据的丢失,大很多就采用:接收 保存成文件 分析 发送这方案好点,除非接收的数据不是重要的数据是可以丢失的。
    另外,保存成文件时可以采用定量保存,譬如:满1M就保存成一个文件。不要考虑多线程,估计问题不在这,除非是多CPU。
      

  17.   

    如果CPU才40%,则估计是因为线程在处理时有过多的等待,看楼主说的情况可能瓶颈在发送到[客户中心]那里。就不知道发送到[客户中心]那里是怎么实现的?
      

  18.   

    1:1分钟收到八万条数据是可以(前提是不对收到数据做处理,但是如果对收到数据,做分析,肯定就不行了。)就是由于对数据分析使接收数据变慢,造从数据丢失。如果不是 很复杂的 分析(如 按bcp的格式化 数据 ) 是没问题的
      

  19.   

    hawk_e2e(hawk_e2e) 提供的意见可以考虑,不过现在看来只有两条路,一个加服务器,另一条是优化处理代码,看能不能把速度提升上来,总之我的目的就是要加快数据的处理速度,如果数据的处理速度提不上来,就很难解决问题(目前这是我个人看法),希望高手能给予帮助。
      

  20.   

    这样的程序,最好不要使用WINdows,windows对进程调度有缺陷,速度有点力不从心。
    你最好采用unix/Linux系统,采用ORACLE数据库。
    1.一个进程负责接受数据,存入接受缓冲区,比如存入文件,达到一定量后,移到业务层,可以按业务分目录。
    2.多个进程负责处理数据,一个业务处理一个目录。处理后数据存入发送给【客户中心】缓冲区
    3.多个进程负责【客户中心】缓冲区发送,批量发送入库。
    应该满足你的要求。
    注意入库:
     1。必须是批量入库,一批提交一次。
     2。不要采用ADO等控件来完成,比如ORACLE采用Pro*c/C++来完成,保证速度和稳定性。
      

  21.   

    ORACLE数据库 +unix/Linux系统
    杀鸡 用 牛刀不采用ADO等控件来完成 是对的
    就是 用 也是用 BULK INSERT
      

  22.   

    1。部分说明部分
    const
      VehicleProto: string = 'udp';
      VehicleUPDAddr: string = '0.0.0.0';
      VehicleUDPPort: string = '4096';
      SizeOfBuff = 10000;
    type
      PUDPBuffRecord = ^TUDPBuffRecord;
      TUDPBuffRecord = record //向上发送数据块
        CData: string;
        StrUDPAdd: string;
        StrUDPPort: Integer;
        CNext: PUDPBuffRecord;
      end;  PVehicleAreaRecord = ^TVehicleAreaRecord;
      TVehicleAreaRecord = record //区域记录
        AreaName: string;
        SmallLongitude: Double;
        BigLongitude: Double;
        SmallLatitude: Double;
        BigLatitude: Double;
        OverSpeed: Integer;
      end;  PVehicleRecord = ^TVehicleRecord;
      TVehicleRecord = record //车记录
        CActionTime: TDateTime;
        StrUDPAddr: string;
        StrUDPPort: Integer;
        CenterIDList: TStringList;
        AreaList: TList;
        IsOnArea: Boolean;
        OnAreaRecord: TVehicleAreaRecord
      end;  TLoginThread = class(TThread)  //车登录线程
      private
        { Private declarations }
        FVehicleIndex: Integer;
        FPVehicleRecord: PVehicleRecord;
        FSendStr: string;
        FAreaList: TList;
        FCenterList: TStringList;
        FDoCurrently: PUDPBuffRecord;
        procedure DoNotifyOrder;
        procedure GetCenterList;  //获取车的中心列表
        procedure GetAreaList;//获取车的区域列表
        procedure AddItem;    //添加车到车列表
        procedure VehicleEvent;
      protected
        procedure Execute; override;
      public
        { Public declarations }
        constructor Create(CreateSuspended: Boolean; PFreeOnTerminate: Boolean;
          PDoCurrently: PUDPBuffRecord);
      end;  TFormMain = class(TForm)
        WSocketVehicle: TWSocket;
        Memo1: TMemo;
        GroupBoxVehicle: TGroupBox;
        ListBoxVehicle: TListBox;
        GroupBoxCenter: TGroupBox;
        ListBoxCenter: TListBox;
        ClientSocketMain: TClientSocket;
        EditIP: TEdit;
        ButtonStart: TButton;
        Label1: TLabel;
        TimerOnlyOne: TTimer;
        Memo2: TMemo;
        Button6: TButton;
        Button7: TButton;
        LabeledEditVehicle: TLabeledEdit;
        LabeledEditCenter: TLabeledEdit;
        EditIPPort: TEdit;
        TimerDoOnLine: TTimer;
        Edit1: TEdit;
        Edit2: TEdit;
        Edit3: TEdit;
        Button1: TButton;
        Button2: TButton;
        Button3: TButton;
        Edit4: TEdit;
        DBGrid1: TDBGrid;
        Edit5: TEdit;
        CheckBox1: TCheckBox;
        CheckBox2: TCheckBox;
        Panel1: TPanel;
        Edit6: TEdit;
        CheckBox3: TCheckBox;
        Panel2: TPanel;
        Panel3: TPanel;
        Button4: TButton;
        Edit7: TEdit;
        procedure FormCreate(Sender: TObject);
        procedure WSocketVehicleSessionConnected(Sender: TObject;
          ErrCode: Word);
        procedure FormDestroy(Sender: TObject);
        procedure WSocketVehicleDataAvailable(Sender: TObject; ErrCode: Word);
        procedure TimerOnlyOneTimer(Sender: TObject);
        procedure ButtonStartClick(Sender: TObject);
        procedure ClientSocketMainConnect(Sender: TObject;
          Socket: TCustomWinSocket);
        procedure ClientSocketMainDisconnect(Sender: TObject;
          Socket: TCustomWinSocket);
        procedure ClientSocketMainError(Sender: TObject;
          Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
          var ErrorCode: Integer);
        procedure ClientSocketMainRead(Sender: TObject;
          Socket: TCustomWinSocket);
        procedure Button6Click(Sender: TObject);
        procedure Button7Click(Sender: TObject);
        procedure Memo1Change(Sender: TObject);
        procedure Memo2Change(Sender: TObject);
        procedure ListBoxVehicleClick(Sender: TObject);
        procedure TimerDoOnLineTimer(Sender: TObject);
        procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        procedure Button3Click(Sender: TObject);
        procedure CheckBox3Click(Sender: TObject);
        procedure Button4Click(Sender: TObject);
      private
        { Private declarations }
        FCount: LongInt;
        FInsertCount: Integer;
        NotInsertedData: Boolean;
        IsInsertData: Boolean;
        LoginThread: TLoginThread;
        PLoginCurrently: PUDPBuffRecord;
        ALogin: array[1..SizeOfBuff] of TUDPBuffRecord;
        IVehicleCurrently: Integer; //车列表当前扫描数
        IsConnected: Boolean; //是否连接
        EmbranchmentID: Integer; //分服务器ID
        MainCenterID: Integer; //总服务器ID
        EmbranchmentIP: string; //分服务器IP
        HeartbeatStr: string; //心跳包
        SelfID: string; //分服务器ID(字符串)
        ResiduaryOrder: string; //剩余指令
        OrderList: TStringList; //总服务器发来的指令列表
        OrderList1: TStringList; //车发来的指令列表
        FStrings: TStringList; //单条指令拆分
        procedure Split(var TempStr: string); //拆分来自总服务器的指令到列表中
        procedure Split1(var TempStr: string); //拆分来自车的指令到列表中
        procedure ScanVehicleList; //扫描车列表
        procedure SaveLogFile(const TempStr: string); //登录信息保存到文本中
        procedure GetCenterList(const ParamTerminalID: string; var
          ParamCenterList: TStringList); //获取车的中心列表
        procedure GetAreaList(const ParamTerminalID: string; var ParamAreaList:
          TList); //获取车的区域列表
        function AvailCoordinate(const ParamLong, ParamLat, ParamSpeed: string):
          Boolean; //判断数据是否漂移
        function IsAreaEvent(var ParamVehicleRecord: PVehicleRecord; const
          ParamEnable: string; const ParamTerminalID: string; //判断是否越区以及是否区域内超速
          var ParamAreaOrder: string): Boolean;
        procedure SetNoAreaEvent; //无越区时区域字段信息的设置
        procedure DoNotifyOrder(const ParamStrings: TStringList; const ParamOrder: //群发消息
          string {; ParamNoCenterID: Boolean = True});
        procedure DoAutoSend(const ParamStrings: TStringList; const ParamOrder: //发给所以自动接收的中心
          string);
      

  23.   

    你好像 喜欢变长 数据 string
    我喜欢直接 字节 流 
    如果 你用string 建议你 找第三方 的 内存管理的 pas 有时可以提高20% 的效率一下 过程要 逐一 优 化
        procedure Split(var TempStr: string); //拆分来自总服务器的指令到列表中
        procedure Split1(var TempStr: string); //拆分来自车的指令到列表中
        procedure ScanVehicleList; //扫描车列表
        procedure SaveLogFile(const TempStr: string); //登录信息保存到文本中
        procedure GetCenterList(const ParamTerminalID: string; var
          ParamCenterList: TStringList); //获取车的中心列表
        procedure GetAreaList(const ParamTerminalID: string; var ParamAreaList:
          TList); //获取车的区域列表
        function AvailCoordinate(const ParamLong, ParamLat, ParamSpeed: string):
          Boolean; //判断数据是否漂移
        function IsAreaEvent(var ParamVehicleRecord: PVehicleRecord; const
          ParamEnable: string; const ParamTerminalID: string; //判断是否越区以及是否区域内超速
          var ParamAreaOrder: string): Boolean;
        procedure SetNoAreaEvent; //无越区时区域字段信息的设置
        procedure DoNotifyOrder(const ParamStrings: TStringList; const ParamOrder: //群发消息
          string {; ParamNoCenterID: Boolean = True});
        procedure DoAutoSend(const ParamStrings: TStringList; const ParamOrder: //发给所以自动接收的中心
          string);
      

  24.   

    TStringList 你用的 多的 话 用 faststrings
      

  25.   


    2 数据接收核心代码      
    procedure TFormMain.WSocketVehicleDataAvailable(Sender: TObject;
      ErrCode: Word);
    var
      ReceiveBuffer: array[0..255] of char;
      ReceiveLen: Integer;
      Src: TSockAddrIn;
      SrcLen: Integer;
      TempStr: string;
      ReceiveStr: string;
      TempPVehicleRecord: PVehicleRecord;
      TempVehicleIndex: Integer;
      I: Integer;
      TempOrder: string;
      //IsNotSend         : Boolean;
      //PosI              : Integer;
      TempAreaOrder: string;
      TempDateTime: TDateTime;
      f: TextFile;
    begin
      NotInsertedData := True;
      SrcLen := SizeOf(Src);
      ReceiveLen := WSocketVehicle.ReceiveFrom(@ReceiveBuffer,
        SizeOf(ReceiveBuffer), Src, SrcLen);
      if ReceiveLen >= 8 then
      begin
        ReceiveBuffer[ReceiveLen] := #0;
        ReceiveStr := ReceiveBuffer;
        if CheckBox2.Checked then
          Memo2.Lines.Add(ReceiveStr);
        try
          Split1(ReceiveStr);
          for I := 0 to OrderList1.Count - 1 do
          begin
            //是合格式数据
            ReceiveLen := Length(OrderList1[I]);
            if AnsiStartsStr('*', OrderList1[I])
              and (ReceiveLen >= 8)
              {and (Pos(#13#10, OrderList1[I]) = 0)}then
            begin
              if (OrderList1[I][8] = ',') or (OrderList1[I][8] = '#') then
              begin
                //Memo2.Lines.Add(OrderList1[I]);
                TempStr := Copy(OrderList1[I], 2, 6);
                if IsStr(TempStr) then
                begin
                  TempVehicleIndex := IndexOf(TempStr, ListBoxVehicle);
                  if TempVehicleindex = -1 then
                  begin
                    AssignFile(f, ExtractFilePath(ParamStr(0)) + 'Login.txt');
                    try
                      Append(f);
                      Writeln(f, '[' + DateTimeToStr(Now()) + '][' + OrderList1[I] +
                        '][' + StrPas(inet_ntoa(Src.sin_addr)) + ':' +
                        IntToStr(ntohs(Src.sin_port)) + ']');
                    finally
                      CloseFile(f);
                    end;
                    PLoginCurrently^.CData := TempStr;
                    PLoginCurrently^.StrUDPAdd := StrPas(inet_ntoa(Src.sin_addr));
                    PLoginCurrently^.StrUDPPort := ntohs(Src.sin_port);
                    //Memo2.Lines.Add(PUpCurrently^.CData);
                    PLoginCurrently := PLoginCurrently^.CNext;
                    InterlockedIncrement(LoginILock);
                    LoginThread.Resume;
                    Exit;
                  end
                  else
                  begin
                    TempPVehicleRecord :=
                      PVehicleRecord(ListBoxVehicle.Items.Objects[TempVehicleIndex]);
                    TempPVehicleRecord^.StrUDPAddr :=
                      StrPas(inet_ntoa(Src.sin_addr));
                    TempPVehicleRecord^.StrUDPPort := ntohs(Src.sin_port);
                    TempPVehicleRecord^.CActionTime := Now;
                    DM.ADOInsert.Append;
                    if ReceiveLen > 11 then
                    begin
                      TempOrder := OrderList1[I];
                      TempVehicleIndex := Pos('@', TempOrder);
                      if TempVehicleIndex > 0 then
                      begin
                        TempOrder[TempVehicleIndex] := 'A';
                      end;
                      TempVehicleIndex := Pos('+', TempOrder);
                      if TempVehicleIndex > 0 then
                      begin
                        TempOrder[TempVehicleIndex] := ',';
                      end;
                      TempVehicleIndex := Pos('-', TempOrder);
                      if TempVehicleIndex > 0 then
                      begin
                        TempOrder[TempVehicleIndex] := '.';
                      end;
      

  26.   

    FStrings.Clear;
                      if ',' = TempOrder[11] then //是否包含中心ID
                      begin //不包含中心ID
                        if ExtractStrings([',', '#'], [#255, '*'],
                          Pointer(TempOrder),
                          FStrings) = 10 then
                        begin
                          if AvailCoordinate(FStrings[FStrings.Count - 4],
                            FStrings[FStrings.Count - 5], FStrings[FStrings.Count
                            - 3]) then
                          begin
                            Insert(',000', TempOrder, 8); //初始化中心ID为000
                            TempAreaOrder := TempOrder;
                            if IsAreaEvent(TempPVehicleRecord,
                              FStrings[FStrings.Count
                              - 6], TempStr, TempAreaOrder) then // 判断是否越区
                            begin
                              if not
                                DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName(
                                '@AreaOverSpeed').Value then 
                                if not DM.ADOInsert.FieldByName('AreaOverSpeed').AsBoolean then
                              begin
                               //没有发生区域超速事件,发送原数据信息 ;
                               //发生区域超速事件,原数据信息在 IsAreaEvent中已经发送
                                DoNotifyOrder(TempPVehicleRecord^.CenterIDList,
                                  TempOrder);
                              end;
                              //发送越区指令
                              DoNotifyOrder(TempPVehicleRecord^.CenterIDList,
                                '*' + TempStr + TempAreaOrder);
                            end
                            else
                            begin
                              if not
                                DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName(
                                '@AreaOverSpeed').Value then
                                 //没有发生区域超速事件,发送原数据信息 ;
                                //发生区域超速事件,原数据信息在 IsAreaEvent中已经发送
                                if 'FF' = FStrings[1] then
                                begin
                                  IsInsertData := True;
                                  //原数据信息群发
                                  DoNotifyOrder(TempPVehicleRecord^.CenterIDList,
                                    TempOrder);
                                end
                                else
                                begin //向自动接收中心发送原数据信息
                                  DoAutoSend(TempPVehicleRecord^.CenterIDList,
                                    TempOrder);
                                end;
                              end;
                            end;
                            IsInsertData := True;
                            if IsInsertData and NotInsertedData then
                            begin
                              if Length(FStrings[FStrings.Count - 1]) =
                                Length(FStrings[FStrings.Count - 7]) then
                              begin //获取卫星时间
                                TempStr := '20' +
                                  FStrings[FStrings.Count - 1][5] +
                                  FStrings[FStrings.Count
                                  - 1][6] + '-' +
                                  FStrings[FStrings.Count - 1][3] +
                                  FStrings[FStrings.Count
                                  - 1][4] + '-' +
                                  FStrings[FStrings.Count - 1][1] +
                                  FStrings[FStrings.Count
                                  - 1][2] + ' ' +
                                  FStrings[FStrings.Count - 7][1] +
                                  FStrings[FStrings.Count
                                  - 7][2] + ':' +
                                  FStrings[FStrings.Count - 7][3] +
                                  FStrings[FStrings.Count
                                  - 7][4] + ':' +
                                  FStrings[FStrings.Count - 7][5] +
                                  FStrings[FStrings.Count
                                  - 7][6];
                                if TryStrToDateTime(TempStr, TempDateTime) then
                                begin
                                  DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName(
                                    '@PlanetTime').Value := TempDateTime;
                                  DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName(
                                    '@Direction').Value :=
                                    StrToIntDef(FStrings[FStrings.Count - 2], 0);
                                  //转化状态位
                                  TempStr := HexToBin(FStrings[2]);
                                  DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName(
                                    '@OverSpeed').Value :=StrToBoolDef(TempStr[8],False);
                                  DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName(
                                    '@Alert').Value := StrToBoolDef(TempStr[7],False);
                                  DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName(
                                    '@CutElectricity').Value :=StrToBoolDef(TempStr[6],False);
                                  DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName(
                                    '@LowerVoltage').Value :=StrToBoolDef(TempStr[5],False);
                                  DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName(
                                    '@ConnectedElectricity').Value :=StrToBoolDef(TempStr[4],False);
                                  DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName(
                                    '@LoadedOn').Value := StrToBoolDef(TempStr[3],False);
                                  DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName(
                                    '@PowerOn').Value := StrToBoolDef(TempStr[2],False);
                          
                                  NotInsertedData := False;
                                  DM.ADOStoredProcInsertPlanetData.ExecProc;
                                 
                                end;
                              end;
                            end;
                          end;
                        end;
                      end
      

  27.   

    AssignFile(f, ExtractFilePath(ParamStr(0)) + 'Login.txt');
                    try
                      Append(f);
                      Writeln(f, '[' + DateTimeToStr(Now()) + '][' + OrderList1[I] +
                        '][' + StrPas(inet_ntoa(Src.sin_addr)) + ':' +
                        IntToStr(ntohs(Src.sin_port)) + ']');
                    finally
                      CloseFile(f);
                    end;一般写文件,如果是频繁作处理的,都使用内存缓存再写。类似:var
      FileHandle: THandle;
      FileBuffer: PChar;
      FileBufVal, FileBufSize: Integer;init file buffer:
      FileBufVal := 0;
      FileBufSize := 1024 * 100;
      FileBuffer := AllocMem(FileBufSize);
      FileHandle := FileOpen('MyFile', fmOpen);procedure WriteDataToFileWithBuffer(buf: PChar; Size: Integer);
    begin
      if (Size <= 0) or (Size + FileBufVal > FileBufSize) then
      begin
        FileWrite(FileHandle, FileBuffer^, FileBufVal);
        FileBufVal := 0;
      end;
      if Size > 0 then
      begin
        Move(Buf, (FileBuffer + FileBufVal)^, Size);
        Inc(FileBufVal, Size);
        (FileBuffer + FileBufVal)^ := #13;
        (FileBuffer + FileBufVal)^[1] := #10;
        Inc(FileBufVal, 2);
      end;
    end;然后在退出再调用一次:
    WriteDataToFileWithBuffer(nil, 0);再写入文件。free:
      CloseHandle(FileHandle);文件IO调用频繁是效率很低的。其它的与DB交互的,你可以另启一个线程,跟你类似LoginThread处理一样。尽量减少通讯层在收发后的处理时间。延后处理。其它的是字符操作,处理实在是看不太明白。再说
      

  28.   

    procedure TFormMain.Split1(var TempStr: string);  //拆分来自车的指令到列表中
    var
      TempI: Integer;
    begin
      OrderList1.Clear;
      TempI := pos('#', TempStr);
      while (TempI > 0) do
      begin
        OrderList1.Add(TrimLeft(copy(TempStr, 1, TempI)));
        Delete(TempStr, 1, TempI);
        TempI := pos('#', TempStr);
      end;
    end;function IndexOf(const S: string; PListBox: TListBox): Integer; //查找车
    var
      Low               : Integer;
      High              : Integer;
      Mid               : Integer;
      TempI             : Integer;
    begin
      Low := 0;
      High := PListBox.Count - 1;
      while Low <= High do
      begin
        Mid := (Low + High) div 2;
        //Mid :=
        TempI := AnsiCompareText(S, PListBox.Items[Mid]);
        if TempI < 0 then
        begin
          High := Mid - 1;                  //若关键字小于mid所指的数
        end
        else if TempI > 0 then
        begin
          Low := Mid + 1;                   //若关键字大于mid所指的数
        end
        else
        begin
          Result := Mid;                    //若关键字等于mid所指的数
          Exit;
        end;
      end;
      Result := -1;
    end;
    function TFormMain.AvailCoordinate(const ParamLong,
      ParamLat, ParamSpeed: string): Boolean; //判断数据是否漂移
    begin
      DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@Speed').Value :=
        StrToIntDef(ParamSpeed, 0);
      DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@Longitude').Value :=
        StrToFloatDef(ParamLong, 0.0);
      DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@Latitude').Value :=
        StrToFloatDef(ParamLat, 0.0);
      if (DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@Longitude').Value
        =
        0.0)
        or
        (DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@Latitude').Value
        =
        0.0) then
      begin
        Result := False;
      end
      else
      begin
        Result := True;
      end; 
    end;
    procedure TFormMain.SetNoAreaEvent; //无越区时区域字段信息的设置
    begin
      DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@EnterArea').Value
        := False;
      DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@LeaveArea').Value
        := False;
      DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@SmallLongitude').Value
        := 0;
      DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@BigLongitude').Value
        := 0;
      DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@SmallLatitude').Value
        := 0;
      DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@BigLatitude').Value
        := 0;
    end;procedure TFormMain.DoNotifyOrder(const ParamStrings: TStringList;
      const ParamOrder: string {; ParamNoCenterID: Boolean = True}); //群发消息
    var
      TempStr: string;
      TempSendStr: string;
      I: Integer;
    begin
      TempStr := ParamOrder;
      for I := ParamStrings.Count - 1 downto 0 do
      begin
        if IndexOf(ParamStrings.Names[I], ListBoxCenter) > -1 then
        begin
          TempStr[9] := ParamStrings.Names[I][1];
          TempStr[10] := ParamStrings.Names[I][2];
          TempStr[11] := ParamStrings.Names[I][3];
          TempSendStr := TempSendStr + TempStr;
        end;
      end;
      ClientSocketMain.Socket.SendText(TempSendStr);
    endprocedure TFormMain.DoAutoSend(const ParamStrings: TStringList;
      const ParamOrder: string); //群发自动接收消息
    var
      TempStr: string;
      TempSendStr: string;
      I: Integer;
    begin
      TempStr := ParamOrder;
      for I := ParamStrings.Count - 1 downto 0 do
      begin
        if (ParamStrings.ValueFromIndex[I] = '-1')
          and (IndexOf(ParamStrings.Names[I], ListBoxCenter) > -1) then
        begin      TempStr[9] := ParamStrings.Names[I][1];
          TempStr[10] := ParamStrings.Names[I][2];
          TempStr[11] := ParamStrings.Names[I][3]; //插入正确的中心ID
          TempSendStr := TempSendStr + TempStr;
        end;
      end;
      ClientSocketMain.Socket.SendText(TempSendStr);
    end;
      

  29.   

    function TFormMain.IsAreaEvent(var ParamVehicleRecord: PVehicleRecord;
      const ParamEnable: string; const ParamTerminalID: string;
      var ParamAreaOrder: string): Boolean; //判断是否越区以及是否区域内超速
    var
      TempIsOnArea: Boolean;
      I: Integer;
      TempPVehicleAreaRecord: PVehicleAreaRecord;
    begin
      DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@AreaName').Value
        := '';
      DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@TerminalID').Value
        := ParamTerminalID; 
      if 'A' = ParamEnable then //判段数据是否导航
      begin //导航数据
        IsInsertData := True;
        DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@IsNavigation').Value
          := True;
        TempIsOnArea := False; //初始化是否在区域变量
        for I := ParamVehicleRecord^.AreaList.Count - 1 downto 0 do //判断是否在区域
        begin
          TempPVehicleAreaRecord := ParamVehicleRecord^.AreaList[I];
          if
            (DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@Longitude').Value
            >= TempPVehicleAreaRecord^.SmallLongitude) and
            (DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@Longitude').Value
            <= TempPVehicleAreaRecord^.BigLongitude) and
            (DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@Latitude').Value
            >= TempPVehicleAreaRecord^.SmallLatitude) and
            (DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@Latitude').Value
            <= TempPVehicleAreaRecord^.BigLatitude) then 
          begin //在区域中
            TempIsOnArea := True;
            //ParamVehicleRecord^.OnAreaRecord := TempPVehicleAreaRecord;
            with ParamVehicleRecord^.OnAreaRecord do
            begin
              AreaName := TempPVehicleAreaRecord^.AreaName;
              SmallLongitude := TempPVehicleAreaRecord^.SmallLongitude;
              BigLongitude := TempPVehicleAreaRecord^.BigLongitude;
              SmallLatitude := TempPVehicleAreaRecord^.SmallLatitude;
              BigLatitude := TempPVehicleAreaRecord^.BigLatitude;
            end; //记录当前所在区域信息到车对象中        if (TempPVehicleAreaRecord^.OverSpeed <> 0) and
              (DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@Speed').Value
              > TempPVehicleAreaRecord^.OverSpeed) then //判断是否区域内超速 
            begin
              DoNotifyOrder(ParamVehicleRecord^.CenterIDList,
                ParamAreaOrder); // 发送本来定位数据
              DoNotifyOrder(ParamVehicleRecord^.CenterIDList,
                '*' + ParamTerminalID + ',000,F8,' +
                TempPVehicleAreaRecord^.AreaName + ',' +
                FloatToStr(TempPVehicleAreaRecord^.SmallLongitude) + ',' +
                FloatToStr(TempPVehicleAreaRecord^.BigLongitude) + ',' +
                FloatToStr(TempPVehicleAreaRecord^.SmallLatitude) + ',' +
                FloatToStr(TempPVehicleAreaRecord^.BigLatitude) + ',' +
                IntToStr(TempPVehicleAreaRecord^.OverSpeed) + '#'
                ); //发送区域内超速指令
              //*E00002,000,F8,AreaName,SmallLongitude,BigLongitude,SmallLatitude,BigLatitude#
              DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName(
                '@AreaName').Value := TempPVehicleAreaRecord^.AreaName;
              DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName(
                '@AreaOverSpeed').Value := True;
            end
            else
            begin
             DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName(
                '@AreaOverSpeed').Value := False; 
            
            end;
            Break;
          end;
        end;
        if ParamVehicleRecord^.IsOnArea then //以前是否在区域中
        begin //以前在区域中
          if not TempIsOnArea then // 现在是否在区域中
          begin //现在不在区域中,发生出区事件
             //设置越区时区域字段信息
            DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@EnterArea').Value
              := False;
            DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@LeaveArea').Value
              := True;
            DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@AreaName').Value
              := ParamVehicleRecord^.OnAreaRecord.AreaName;
            DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@SmallLongitude').Value
              := ParamVehicleRecord^.OnAreaRecord.SmallLongitude;
            DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@BigLongitude').Value
              := ParamVehicleRecord^.OnAreaRecord.BigLongitude;
            DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@SmallLatitude').Value
              := ParamVehicleRecord^.OnAreaRecord.SmallLatitude;
            DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@BigLatitude').Value
              := ParamVehicleRecord^.OnAreaRecord.BigLatitude;
            //OnAreaRecord^.AreaSN
            DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName(
              '@AreaOverSpeed').Value := False;               ParamAreaOrder := ',000,FE,0,' +
              ParamVehicleRecord^.OnAreaRecord.AreaName
              + ',' + FloatToStr(ParamVehicleRecord^.OnAreaRecord.SmallLongitude)
              + ',' + FloatToStr(ParamVehicleRecord^.OnAreaRecord.BigLongitude)
              + ',' + FloatToStr(ParamVehicleRecord^.OnAreaRecord.SmallLatitude)
              + ',' + FloatToStr(ParamVehicleRecord^.OnAreaRecord.BigLatitude)
              + '#'; //记录出区指令
            ParamVehicleRecord.IsOnArea := TempIsOnArea;
            Result := True;
          end
          else
          begin //现在区域中
            SetNoAreaEvent; //设置没有越区时区域字段信息
            Result := False;
          end;
        end
        else
        begin //以前没有在区域中
          if TempIsOnArea then //现在是否在区域中
          begin //现在在区域中
            //设置越区时区域字段信息
            DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@EnterArea').Value
              := True;
            DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@LeaveArea').Value
              := False;
            DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@AreaName').Value
              := ParamVehicleRecord^.OnAreaRecord.AreaName;
            DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@SmallLongitude').Value
              := ParamVehicleRecord^.OnAreaRecord.SmallLongitude;
            DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@BigLongitude').Value
              := ParamVehicleRecord^.OnAreaRecord.BigLongitude;
            DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@SmallLatitude').Value
              := ParamVehicleRecord^.OnAreaRecord.SmallLatitude;
            DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@BigLatitude').Value
              := ParamVehicleRecord^.OnAreaRecord.BigLatitude; 
            ParamAreaOrder := ',000,FE,1,'
              + ParamVehicleRecord^.OnAreaRecord.AreaName
              + ',' + FloatToStr(ParamVehicleRecord^.OnAreaRecord.SmallLongitude)
              + ',' + FloatToStr(ParamVehicleRecord^.OnAreaRecord.BigLongitude)
              + ',' + FloatToStr(ParamVehicleRecord^.OnAreaRecord.SmallLatitude)
              + ',' + FloatToStr(ParamVehicleRecord^.OnAreaRecord.BigLatitude)
              + '#'; //记录入区指令
            ParamVehicleRecord.IsOnArea := TempIsOnArea;
            Result := True;
          end
          else
          begin
            SetNoAreaEvent; //设置没有越区时区域字段信息
            DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName(
              '@AreaOverSpeed').Value := False;
          
            Result := False;
          end;
        end;
      end
      else
      begin //非导航数据
        IsInsertData := False;
        DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName('@IsNavigation').Value
          := False;
        SetNoAreaEvent; //设置非导航时区域字段信息
        DM.ADOStoredProcInsertPlanetData.Parameters.ParamByName(
          '@AreaOverSpeed').Value := False;
        Result := False;
      end;
    end;
      

  30.   

    改内存表估计数据量太大,如果数据量不大的话,还可以做。这些代码与DB,界面的Component交互太多,作起来太累,我只能说我看起业累,一时也说不清了。作通讯相关,如果量大,且又与DB打交道的话,我只能说你楼主开始说的情况不发生才怪。优化的结果实在有限,且不说给别人优化是费力不讨发的工作。一句话,前期工作没做好,没判断量大的情况,程序架构对效率的影响。关键代码不应与DB,界面组件发生关系,只能与内存或缓冲间作作处理。不知怎么跟你说了。
      

  31.   

    我是这样写通讯处理的:
    一:
    定义协议,定义双方通讯的协议处理包,类似:包头:
      TMyDataHeader = packed record
        len: Integer;
        cmd: Integer;
      end包体:
      PLoginData = ^TLoginData;
      TLoginData = paced record
        name: array [0..10] of char;
        pass: array [0..10] of char;
      end;完整包:
      TMyDataPacket = packed record
        Hdr: TMyDataHeader;
        case Integer of
          0: (LoginData: TLoginData);
          1: (Other: TOtherData);
      end;
    一个数据包==> 包头+包体,包长度由包头.len控制,包体的内容结构由包头.cmd控制。
    这样,我再写两个函数来控制包的发送和接收:
    function SendDataPacket(Data: PMyDataPacket): Boolean;
    function RecvDataPacket(Data: PMyDataPacket): Boolean;这样的好处是什么了?就是包接收,或包打包的过程,只要针对于一个结构的某字段就行。
    StrCopy('username', logindata.user);再直接访问:Logindata.user而不是你上面所写的解析来解析去,再去一点点处理,给人很明了的感觉。随便说说,你的程序已经写了那些多,也不好改,再说。
      

  32.   

    ERR0RC0DE() 说得很对,你说的就是原因的根本 ,我决定开始改了,随便减少几句和DB交互的代码,效果明显,谢谢你 ,嘿嘿 希望大家,以后记住,我肯定会记住。