unit uTCPDevice; interface uses System.Win.ScktComp,uSafeLog,uErrorInfo,System.SysUtils,FMX.Types, System.StrUtils,System.Classes,WinSock,WinSock2,Winapi.Windows; Const IOC_IN = $80000000; IOC_VENDOR = $18000000; IOC_out = $40000000; SIO_KEEPALIVE_VALS = IOC_IN or IOC_VENDOR or 4; DATA_BUFSIZE = 8192; type TTCP_KEEPALIVE = packed record onoff: integer; keepalivetime: integer; keepaliveinterval: integer; end; TWorkEvent = procedure(sValue:string) of object; T2DWorkEvent = procedure(Sender: TObject;sValue:string) of object; TThreadX = class(TThread) private FProc: TProc; AValue:T; protected procedure Execute; override; public constructor Create(const AProc: TProc;ProcPar:T); end; TThreadHelper= class helper for TThread public class function CreateThreadX(const ThreadProc: TProc;proPar:T): TThread; static; end; TRfid=class //RFID private bIsDestory:boolean; FOnWork:TWorkEvent; FOnShowState:TWorkEvent; FTimer: TTimer; FPreValue:string; //保存前一个标签值 FSocket:TClientSocket; procedure TimerTimer(Sender: TObject); //判断连接状态,断开的话,自动重连 procedure SocketRead(Sender: TObject; Socket: TCustomWinSocket); //读缓存数据 procedure SocketError(Sender: TObject; Socket: TCustomWinSocket; //出错代码处理 ErrorEvent: TErrorEvent; var ErrorCode: Integer); procedure SocketConnect(Sender: TObject; Socket: TCustomWinSocket); procedure SocketDisConnect(Sender: TObject; Socket: TCustomWinSocket); procedure SocketConnecting(Sender: TObject; Socket: TCustomWinSocket); procedure SendBtye(sValue: String); public constructor Create(sIp:string;iPort:integer); destructor Destroy; override; procedure Close(); procedure Connect(); property OnWork: TWorkEvent read FOnWork write FOnWork;//业务处理事件 property OnShowState:TWorkEvent read FOnShowState write FOnShowState;//显示连接断开提示 procedure SendStr(sValue:String); // procedure ReadData; end; TNumEnce=class //采集器 private bIsDestory:boolean; FOnWork:TWorkEvent; FOnShowState:TWorkEvent; FTimer: TTimer; FPreValue:string; //保存前一个值 FSocket:TClientSocket; FCount:Integer; procedure TimerTimer(Sender: TObject); //判断连接状态,断开的话,自动重连 procedure SocketRead(Sender: TObject; Socket: TCustomWinSocket); //读缓存数据 procedure SocketError(Sender: TObject; Socket: TCustomWinSocket; //出错代码处理 ErrorEvent: TErrorEvent; var ErrorCode: Integer); procedure SocketConnect(Sender: TObject; Socket: TCustomWinSocket); procedure SocketDisConnect(Sender: TObject; Socket: TCustomWinSocket); procedure SocketConnecting(Sender: TObject; Socket: TCustomWinSocket); public constructor Create(sIp:string;iPort:integer); destructor Destroy; override; procedure Close(); procedure Connect(); property OnWork: TWorkEvent read FOnWork write FOnWork;//业务处理事件 property OnShowState:TWorkEvent read FOnShowState write FOnShowState;//显示连接断开提示 property Count: Integer read FCount write FCount; Function Check(sValue:string;iPos:Integer):boolean; //判断返回字符串具体位为1还是0,返回真为1 procedure SendStr(sValue:String); procedure SendStr8(sValue:String); end; T2DCode=class //2D读头 private bIsDestory:boolean; FTimer: TTimer; FOnWork:T2DWorkEvent; FOnShowState:TWorkEvent; FSocket:TClientSocket; FNum:Integer; //编号 procedure SetKeepAlive(Socket: TCustomWinSocket); procedure TimerTimer(Sender: TObject); //判断连接状态,断开的话,自动重连 procedure SocketRead(Sender: TObject; Socket: TCustomWinSocket); //读缓存数据 procedure SocketError(Sender: TObject; Socket: TCustomWinSocket; //出错代码处理 ErrorEvent: TErrorEvent; var ErrorCode: Integer); procedure SocketConnect(Sender: TObject; Socket: TCustomWinSocket); procedure SocketDisConnect(Sender: TObject; Socket: TCustomWinSocket); procedure SocketConnecting(Sender: TObject; Socket: TCustomWinSocket); public property Num:Integer read FNum write FNum; constructor Create(sIp:string;iPort:integer); destructor Destroy; override; procedure Close(); procedure Connect(); procedure DisConnect(); property OnWork: T2DWorkEvent read FOnWork write FOnWork;//业务处理事件 property OnShowState:TWorkEvent read FOnShowState write FOnShowState;//显示连接断开提示 procedure Open; end; implementation constructor TThreadX.Create(const AProc: TProc;ProcPar:T); begin inherited Create(True); FreeOnTerminate := True; FProc := AProc; Avalue:=ProcPar; end; procedure TThreadX.Execute; begin inherited; FProc(Avalue); end; class function TThreadHelper.CreateThreadX(const ThreadProc: TProc; proPar: T): TThread; begin Result := TThreadX.Create(ThreadProc,proPar); end; //////////////////////////////////////////////////////////////////////////////// constructor TRfid.Create(sIp:string;iPort:integer); //参数固定 begin inherited Create; bIsDestory:=false; WorkLog.Debug('创建RFID读卡器'); FSocket:=TClientSocket.Create(nil); FSocket.OnRead:=SocketRead; FSocket.OnError:=SocketError; FSocket.OnConnect:=SocketConnect; FSocket.OnDisconnect:=SocketDisConnect; FSocket.OnConnecting:=SocketConnecting; FSocket.Address:=sIp; FSocket.Port:=iPort; FTimer:=TTimer.Create(nil); FTimer.OnTimer:=TimerTimer; FTimer.Enabled:=true; WorkLog.Debug('连接RFID读卡器:%s,%d',[sIp,iPort]); FPreValue:=''; end; procedure TRfid.Connect(); var tmp:string; begin tmp:=Format('连接RFID读卡器:%s,%d',[FSocket.Address,FSocket.Port]); WorkLog.Debug(tmp); if Assigned(FOnShowState) then FOnShowState(tmp); FSocket.Active:=true; end; procedure TRfid.SocketConnecting(Sender: TObject; Socket: TCustomWinSocket); begin WorkLog.Debug('RFID读卡器连接中...'); if Assigned(FOnShowState) then FOnShowState('RFID读卡器连接中...'); end; procedure TRfid.Close(); begin FTimer.Enabled:=false; FSocket.Close; end; destructor TRfid.Destroy; begin bIsDestory:=true; FSocket.Close; FTimer.Enabled:=false; WorkLog.Debug('销毁RFID读卡器'); FSocket.Free; FTimer.Free; inherited Destroy; end; procedure TRfid.SocketDisConnect(Sender: TObject; Socket: TCustomWinSocket); begin WorkLog.Debug('RFID读卡器连接断开'); if Assigned(FOnShowState) then FOnShowState('RFID读卡器连接断开'); end; procedure TRfid.TimerTimer(Sender: TObject); begin if FTimer.Enabled then begin FTimer.Enabled:=false; FSocket.Close; FSocket.Open; end; end; procedure TRfid.SocketRead(Sender: TObject; Socket: TCustomWinSocket); var buf:array[0..1024] of byte; sHexString:string; i:Integer; sData:string; //标签数据 function ByteToString(const Value:PByte;iLen:Integer): String; var I: integer; S : String; begin S := ''; for I := 0 to iLen-1 do begin S := S+Chr(Value[I]); end; Result := S; end; begin if bIsDestory then Exit; sHexString:=''; for i:= 0 to Socket.ReceiveBuf(buf,1024) do begin sHexString:=sHexString+buf[i].ToHexString; end; WorkLog.Debug('RFID读到数据:%s',[sHexString]); //1B3501FF1F0012BE3800413346564646473246413033300000413346564646473246413033A41B3501FF03000100000100 //数据包的第7位,代表包数据长度 if (buf[0]=$1B) and ((buf[1]=$35) or (buf[1]=$39)) then // 1B 39 包头 (buf[1]=$39) and (buf[6]<20) and (buf[6]>8) begin sData:=ByteToString(@buf[10],buf[6]-3); if sData<>FPreValue then //判断重复 begin if sData.Length>8 then//保证数据有效 FPreValue:=sData; //开启连接数据库线程 if Assigned(FOnWork) then TThread.CreateThreadX(FOnWork,sData).Start; WorkLog.Debug('RFID数据:%s',[sData]); end else WorkLog.Debug('RFID数据重复:%s',[sData]); end; end; procedure TRfid.SocketError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); var tmpError:string; begin if (ErrorCode=10060) OR (ErrorCode=10065) then begin tmpError:=Format('RFID连接出错(%d):%s',[ErrorCode,SysErrorMessage(ErrorCode)]); if Assigned(FOnShowState) then FOnShowState('RFID连接失败,重新连接'); end else begin tmpError:=Format('RFID连接出错(%d):%s',[ErrorCode,SysErrorMessage(ErrorCode)]); if Assigned(FOnShowState) then FOnShowState('RFID连接出错:'+SysErrorMessage(ErrorCode)); end; workLog.Error('Rfid.SocketError:'+tmpError); ErrorCode:=0; FTimer.Enabled:=true; end; procedure TRfid.SocketConnect(Sender: TObject; Socket: TCustomWinSocket); begin WorkLog.Debug('RFID连接成功'); if Assigned(FOnShowState) then FOnShowState('RFID连接成功'); end; procedure TRfid.SendStr(sValue:String); //Send 1b 35 00 00 08 00 01 02 06 00 00 00 00 00 05 VAR bBtye:array[0..6] of byte; i:integer; begin if bIsDestory or (Length(sValue)>7) then Exit; WorkLog.Debug(Format('下发指令Rfid:%s',[sValue])); for I := 0 to Length(sValue)-1 do bBtye[i]:=Ord(sValue[i+1]); // bBtye[0]:=Ord(sValue[1]);bBtye[1]:=Ord(sValue[1]);bBtye[2]:=$31; // bBtye[3]:=$31;bBtye[4]:=$31;bBtye[5]:=$30; // bBtye[6]:=$30; FSocket.Socket.SendText(sValue); // FSocket.Socket.SendBuf(bBtye[0],Length(bBtye)); // FSocket.Socket.SendText('#011300'); end; procedure TRfid.SendBtye(sValue:String); //Send 1b 35 00 00 08 00 01 02 06 00 00 00 00 00 05 VAR bBtye:array of byte; i,ilenNo:integer; begin if bIsDestory then Exit; WorkLog.Debug(Format('下发指令Rfid:%s',[sValue])); SetLength(bBtye,Length(sValue) div 2); ilenNo:= 0; for I := 1 to Length(sValue) do if i mod 2 =0 then begin bBtye[ilenNo]:=StrToInt('$'+sValue[i-1]+sValue[i]); inc(ilenNo); end; // bBtye[0]:=Ord(sValue[1]);bBtye[1]:=Ord(sValue[1]);bBtye[2]:=$31; // bBtye[3]:=$31;bBtye[4]:=$31;bBtye[5]:=$30; // bBtye[6]:=$30; // FSocket.Socket.SendText(sValue); FSocket.Socket.SendBuf(bBtye[0],Length(bBtye)); // FSocket.Socket.SendText('#011300'); end; procedure TRfid.ReadData(); begin SendBtye('1b 35 00 00 08 00 01 02 06 00 00 00 00 00 05'.Replace(' ','')); end; //////////////////////////////////////////////////////////////////////////////// constructor TNumEnce.Create(sIp:string;iPort:integer); //参数固定 begin inherited Create; bIsDestory:=false; WorkLog.Debug('创建采集器'); FSocket:=TClientSocket.Create(nil); FSocket.OnRead:=SocketRead; FSocket.OnError:=SocketError; FSocket.OnConnect:=SocketConnect; FSocket.OnDisconnect:=SocketDisConnect; FSocket.OnConnecting:=SocketConnecting; FSocket.Address:=sIp; FSocket.Port:=iPort; FTimer:=TTimer.Create(nil); FTimer.OnTimer:=TimerTimer; FTimer.Enabled:=true; WorkLog.Debug('连接采集器:%s,%d',[sIp,iPort]); FPreValue:=''; FCount:=0; end; procedure TNumEnce.Close(); begin FTimer.Enabled:=false; FSocket.Close; end; procedure TNumEnce.Connect(); var tmp:string; begin tmp:=Format('连接采集器:%s,%d',[FSocket.Address,FSocket.Port]); WorkLog.Debug(tmp); if Assigned(FOnShowState) then FOnShowState(tmp); try FSocket.Active:=true; except WorkLog.error('NumEnce.Connect:'+'Connect()'); end; end; procedure TNumEnce.SocketConnecting(Sender: TObject; Socket: TCustomWinSocket); begin WorkLog.Debug('采集器连接中...'); if Assigned(FOnShowState) then FOnShowState('采集器连接中...'); end; destructor TNumEnce.Destroy; begin bIsDestory:=true; FSocket.Close; FTimer.Enabled:=false; WorkLog.Debug('销毁采集器'); FSocket.Free; FTimer.Free; inherited Destroy; end; procedure TNumEnce.SocketDisConnect(Sender: TObject; Socket: TCustomWinSocket); begin WorkLog.Debug('采集器连接断开'); if Assigned(FOnShowState) then FOnShowState('采集器连接断开'); end; procedure TNumEnce.TimerTimer(Sender: TObject); begin if FTimer.Enabled then begin FTimer.Enabled:=false; FSocket.Close; FSocket.Open; end; end; procedure TNumEnce.SocketRead(Sender: TObject; Socket: TCustomWinSocket); var buf:array[0..1024] of byte; sHexString:string; i:Integer; sData:string; function ByteToString(const Value:PByte;iLen:Integer): String; var I: integer; S : String; begin S := ''; for I := 0 to iLen-1 do begin if Value[i]=$0D then break; S := S+Chr(Value[I]); end; Result := S; end; begin if bIsDestory then Exit; sHexString:=''; for i:= 0 to Socket.ReceiveBuf(buf,1024) do begin sHexString:=sHexString+buf[i].ToHexString; end; if (buf[0]=$3E) then // 3E 包头 begin sData:=ByteToString(@buf[0],Length(sHexString) div 2-2); //18位 if sData<>FPreValue then //判断重复 begin FPreValue:= sData; WorkLog.Debug('采集器读到数据:%s',[sHexString]); if Assigned(FOnWork) then FOnWork(sData); //WorkLog.Debug('采集器数据:%s,计数:%d',[sData,FCount]); end; //else // WorkLog.Debug('RFID采集卡数据重复:%s',[sData]); end; end; procedure TNumEnce.SocketError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); var tmpError:string; begin if (ErrorCode=10060) OR (ErrorCode=10065) then begin tmpError:=Format('采集器连接出错(%d):%s',[ErrorCode,SysErrorMessage(ErrorCode)]); if Assigned(FOnShowState) then FOnShowState('采集器连接失败,重新连接'); end else begin tmpError:=Format('采集器连接出错(%d):%s',[ErrorCode,SysErrorMessage(ErrorCode)]); if Assigned(FOnShowState) then FOnShowState('采集器连接出错:'+SysErrorMessage(ErrorCode)); end; workLog.Error('SocketError'+tmpError); ErrorCode:=0; FTimer.Enabled:=true; end; procedure TNumEnce.SocketConnect(Sender: TObject; Socket: TCustomWinSocket); begin WorkLog.Debug('采集器连接成功'); if Assigned(FOnShowState) then FOnShowState('采集器连接成功'); end; Function TNumEnce.Check(sValue:string;iPos:Integer):boolean; BEGIN if length(sValue)=18 then //判断返回位数为18位 Result:=MidStr(sValue,(19-iPos),1)='1' else WorkLog.Error('采集器返回的数据异常'); END; procedure TNumEnce.SendStr8(sValue:String); //Send #011300 VAR bBtye:array[0..7] of byte; i:integer; begin if bIsDestory or (Length(sValue)<8) then begin WorkLog.Error(Format('下发指令采集器错误:%s,%s,%s',[bIsDestory.ToString,Length(sValue).ToString,sValue])); Exit; end; for I := 0 to Length(sValue)-1 do bBtye[i]:=Ord(sValue[i+1]); // bBtye[0]:=Ord(sValue[1]);bBtye[1]:=Ord(sValue[1]);bBtye[2]:=$31; // bBtye[3]:=$31;bBtye[4]:=$31;bBtye[5]:=$30; // bBtye[6]:=$30; FSocket.Socket.SendText(sValue); // FSocket.Socket.SendBuf(bBtye[0],Length(bBtye)); // FSocket.Socket.SendText('#011300'); WorkLog.Debug(Format('下发指令采集器:%s',[sValue])); end; procedure TNumEnce.SendStr(sValue:String); //Send #011300 VAR bBtye:array[0..6] of byte; i:integer; begin if bIsDestory or (Length(sValue)<7) then begin WorkLog.Error(Format('下发指令采集器错误:%s,%s,%s',[bIsDestory.ToString,Length(sValue).ToString,sValue])); Exit; end; for I := 0 to Length(sValue)-1 do bBtye[i]:=Ord(sValue[i+1]); // bBtye[0]:=Ord(sValue[1]);bBtye[1]:=Ord(sValue[1]);bBtye[2]:=$31; // bBtye[3]:=$31;bBtye[4]:=$31;bBtye[5]:=$30; // bBtye[6]:=$30; FSocket.Socket.SendText(sValue); // FSocket.Socket.SendBuf(bBtye[0],Length(bBtye)); // FSocket.Socket.SendText('#011300'); WorkLog.Debug(Format('下发指令采集器:%s',[sValue])); end; /////////////////////////////////////////////////////////////////////////////// constructor T2DCode.Create(sIp:string;iPort:integer); //参数固定 begin inherited Create; bIsDestory:=false; FNum:=1; WorkLog.Debug('创建2D读头'+sIp+','+IntToStr(iPort)); FSocket:=TClientSocket.Create(nil); FSocket.OnRead:=SocketRead; FSocket.OnError:=SocketError; FSocket.OnConnect:=SocketConnect; FSocket.OnDisconnect:=SocketDisConnect; FSocket.OnConnecting:=SocketConnecting; FSocket.Address:=sIp; FSocket.Port:=iPort; FTimer:=TTimer.Create(nil); FTimer.OnTimer:=TimerTimer; FTimer.Enabled:=false; end; procedure T2DCode.Connect(); var tmp:string; begin tmp:=Format('连接2D读头%d:%s,%d',[FNum,FSocket.Address,FSocket.Port]); WorkLog.Debug(tmp); if Assigned(FOnShowState) then FOnShowState(tmp); FSocket.Active:=true; end; procedure T2DCode.DisConnect(); begin FSocket.Close; FTimer.Enabled:=false; end; procedure T2DCode.SocketConnecting(Sender: TObject; Socket: TCustomWinSocket); begin WorkLog.Debug(Format('2D读头%d连接中...',[FNum])); if Assigned(FOnShowState) then FOnShowState(Format('2D读头%d连接中...',[FNum])); end; destructor T2DCode.Destroy; begin bIsDestory:=true; FSocket.Close; FTimer.Enabled:=false; WorkLog.Debug('销毁2D读头'); FSocket.Free; FTimer.Free; inherited Destroy; end; procedure T2DCode.SocketDisConnect(Sender: TObject; Socket: TCustomWinSocket); begin WorkLog.Debug(Format('2D读头%d连接断开',[FNum])); if Assigned(FOnShowState) then FOnShowState(Format('2D读头%d连接断开',[FNum])); end; procedure T2DCode.SetKeepAlive(Socket: TCustomWinSocket); var opt:DWORD; klive, outKlive: TTCP_KEEPALIVE; i,j:integer; // OptVal: DWORD; begin opt := 1; if setsockopt(Socket.SocketHandle,SOL_SOCKET, SO_KEEPALIVE, PAnsiChar(@opt), SizeOf(opt)) = SOCKET_ERROR then begin //showInfo(Format('WinSock Error %d', [WSAGetLastError()])); end; klive.onoff := 1; klive.keepalivetime := 5000; klive.keepaliveinterval := 1; if WSAIoctl(Socket.SocketHandle, SIO_KEEPALIVE_VALS, PAnsiChar(@klive), SizeOf(TTCP_KEEPALIVE), PAnsiChar(@outKlive), SizeOf(TTCP_KEEPALIVE), opt,0,nil) = SOCKET_ERROR then begin //showInfo(Format('WinSock Error %d', [WSAGetLastError()])); end; end; procedure T2DCode.TimerTimer(Sender: TObject); begin if FTimer.Enabled then begin FTimer.Enabled:=false; FSocket.Close; FSocket.Open; end; end; procedure T2DCode.SocketRead(Sender: TObject; Socket: TCustomWinSocket); var buf:array[0..1024] of byte; sHexString:string; i:Integer; sData:string; function ByteToString(const Value:PByte;iLen:Integer): String; var I: integer; S : String; begin S := ''; for I := 0 to iLen-1 do begin if Value[i]=$0D then break; S := S+Chr(Value[I]); end; Result := S; end; begin if bIsDestory then Exit; sHexString:=''; for i:= 0 to Socket.ReceiveBuf(buf,1024) do begin sHexString:=sHexString+buf[i].ToHexString; end; WorkLog.Debug('2D读头%d读到数据:%s',[FNum,sHexString]); sData:=ByteToString(@buf[0],Length(sHexString) div 2); if Assigned(FOnWork) then FOnWork(self,sData); end; procedure T2DCode.SocketError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); var tmpError:string; begin if (ErrorCode=10060) OR (ErrorCode=10065) then begin tmpError:=Format('2D读头%d连接出错(%d):%s',[FNum,ErrorCode,SysErrorMessage(ErrorCode)]); if Assigned(FOnShowState) then FOnShowState(Format('2D读头%d连接失败,重新连接',[FNum])); end else begin tmpError:=Format('2D读头%d连接出错(%d):%s',[FNum,ErrorCode,SysErrorMessage(ErrorCode)]); if Assigned(FOnShowState) then FOnShowState('2D读头连接出错:'+SysErrorMessage(ErrorCode)); end; workLog.Error('2DCode.SocketError:'+tmpError); ErrorCode:=0; if bIsDestory then Exit; FTimer.Enabled:=true; end; procedure T2DCode.SocketConnect(Sender: TObject; Socket: TCustomWinSocket); begin WorkLog.Debug(Format('2D读头%d连接成功',[FNum])); if Assigned(FOnShowState) then FOnShowState(Format('2D读头%d连接成功',[FNum])); end; procedure T2DCode.Close; //4C4F46460D VAR bBtye:array[0..4] of byte; begin if bIsDestory then Exit; bBtye[0]:=$4C;bBtye[1]:=$4F;bBtye[2]:=$46; bBtye[3]:=$46;bBtye[4]:=$0D; fSocket.Socket.SendBuf(bBtye[0],5); WorkLog.Debug(Format('2D读头%d关闭',[FNum])); end; procedure T2DCode.Open; //4C4F4E0d VAR bBtye:array[0..4] of byte; begin if bIsDestory then Exit; bBtye[0]:=$4C;bBtye[1]:=$4F;bBtye[2]:=$4E; bBtye[3]:=$0D; fSocket.Socket.SendBuf(bBtye[0],4); WorkLog.Debug(Format('2D读头%d打开',[FNum])); end; end.