通讯协议:UDP
通讯架构:车----->服务器---->客户中心
【汽车】向【服务器】发数据,【服务器】收到数据后处理,在发送给【客户中心】
1、有2万辆汽车,每辆平均一分钟向服务气发送四条数据,也就是说服务一分钟内收到8万条数据。
2、服务器处理一条数据的平均时间,大约10毫秒,也就是说一分大约处理6000条数据(包括处理完后发送给【客户中心】)。
3、引发问题:由如服务器处理速度慢于接收速度,就引发大量数据丢失。
4、我的解决方案是:服务器收到数据后,不进行处理,把数据放到一个数据缓冲区里面(这样可以保证数据不被丢失),在采取多线程处理数据,设想如果一个线程一分钟能处理六千条,四个处理线程就可以搞定,但是发现多个线程处理,在单CPU的情况比一个线程处理好像还好慢,个人估计是由如线程之间同学协调,和线程切换引起。这样就引起另一个情况,由如处理速度,没有提升上来,数据缓冲区将不断增加,最后引起内存不够,而死掉。
对以上情况现在求解决方案:
解决方案前提:不加增加服务器数量(服务器是IBM的专用服务器)。
解决后重谢!如果有兴趣可以加本人QQ讨论也可以,QQ:63731429。
通讯架构:车----->服务器---->客户中心
【汽车】向【服务器】发数据,【服务器】收到数据后处理,在发送给【客户中心】
1、有2万辆汽车,每辆平均一分钟向服务气发送四条数据,也就是说服务一分钟内收到8万条数据。
2、服务器处理一条数据的平均时间,大约10毫秒,也就是说一分大约处理6000条数据(包括处理完后发送给【客户中心】)。
3、引发问题:由如服务器处理速度慢于接收速度,就引发大量数据丢失。
4、我的解决方案是:服务器收到数据后,不进行处理,把数据放到一个数据缓冲区里面(这样可以保证数据不被丢失),在采取多线程处理数据,设想如果一个线程一分钟能处理六千条,四个处理线程就可以搞定,但是发现多个线程处理,在单CPU的情况比一个线程处理好像还好慢,个人估计是由如线程之间同学协调,和线程切换引起。这样就引起另一个情况,由如处理速度,没有提升上来,数据缓冲区将不断增加,最后引起内存不够,而死掉。
对以上情况现在求解决方案:
解决方案前提:不加增加服务器数量(服务器是IBM的专用服务器)。
解决后重谢!如果有兴趣可以加本人QQ讨论也可以,QQ:63731429。
解决方案 »
- quickreport不是很会用,会的进来指点下
- 祝贺月亮大喜!
- 在delphi中如何修改一个注册表不中KEY 中的一个参数值 ,以及增加与册除KEY 的参数,要求不要叫删除了KYE 后新建
- 兼职DELPHI(成都)
- SQL表达式问题
- 请教Ado问题
- 我已无计可施,在win2000下MTS组见无法跟踪
- 江湖救急!--关于一个经其它字段计算而得的字段的问题
- 工程在delphi2007下编译已经通过了,run后出现下面信息。高手指点
- 请大家提供一点思路,一定给分,说话算话
- TCP/IP 施耐德PLC 通讯问题
- 现在的网络游戏密码登录窗口,都是画出来的,用SPY++什么也查不到,请问下,对于画出来的'edit' 如何取得‘edit’里面的内容
多线程提高效率的方式是由多个线程对各种资源(计算资源CPU、网络资源、硬盘IO资源、数据库等)进行时分复用,而线程并发度受速度最慢的资源的上限限制,假如你的数据库并发IO速度最大1万条数据/分,那么服务器撑死也只能处理到1万条/分
线程间使用互斥,昨界之间的,速度真是会慢下来,再加上处理没写好的话。 或者说你将那需要10ms的处理发上来看看。
写个FIFO的东西,应该很简单,只要注意些内存缓冲,效率会快好多。
indy 做 server 不好1、有2万辆汽车,每辆平均一分钟向服务气发送四条数据,也就是说服务一分钟内收到8万条数据。
这个 似乎 不难 我今天 晚上 写写demo 看看
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.
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.
我是转存成 文件了
数据入库 可以 交给 另外的 程序 处理 可以不用文件 用共享内存。所以 服务一分钟内收到8万条数据 根本不难
现在 的 问题 实际上 是 数据库 快速 数据插入
了 你用 sql 一条数据一条数据 的插入 那是 肯定 不行的
你可以 直接 用 bcp ,BULK INSERT
或者 直接引用sql的dll可以看 sql server 提供 的 c代码
最后还是先写到文件,再每晚定时insert到数据库,能不与DB交互就尽量不交互,或延后处理。
1.单独做线程,只接收数据,统计接收速度,把数据保存文件。
2.单独做线程,从文件中读取数据,分析,发送,统计处理速度。如果2速度<=1速度,则不需要考虑多线程,因为会更慢(对于单CPU),只能改进硬件或改进分析方法或发送方法另2速度大幅提高。
如果2速度>1速度,还要看大多少,大一点点可能会造成接收数据的丢失,大很多就采用:接收 保存成文件 分析 发送这方案好点,除非接收的数据不是重要的数据是可以丢失的。
另外,保存成文件时可以采用定量保存,譬如:满1M就保存成一个文件。不要考虑多线程,估计问题不在这,除非是多CPU。
你最好采用unix/Linux系统,采用ORACLE数据库。
1.一个进程负责接受数据,存入接受缓冲区,比如存入文件,达到一定量后,移到业务层,可以按业务分目录。
2.多个进程负责处理数据,一个业务处理一个目录。处理后数据存入发送给【客户中心】缓冲区
3.多个进程负责【客户中心】缓冲区发送,批量发送入库。
应该满足你的要求。
注意入库:
1。必须是批量入库,一批提交一次。
2。不要采用ADO等控件来完成,比如ORACLE采用Pro*c/C++来完成,保证速度和稳定性。
杀鸡 用 牛刀不采用ADO等控件来完成 是对的
就是 用 也是用 BULK INSERT
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);
我喜欢直接 字节 流
如果 你用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);
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;
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
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处理一样。尽量减少通讯层在收发后的处理时间。延后处理。其它的是字符操作,处理实在是看不太明白。再说
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;
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;
一:
定义协议,定义双方通讯的协议处理包,类似:包头:
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而不是你上面所写的解析来解析去,再去一点点处理,给人很明了的感觉。随便说说,你的程序已经写了那些多,也不好改,再说。