我正在尝试编写一个小的蓝牙协议,用于从Android设备向Windows设备发送B64编码的消息,反之亦然。 为此,我使用封装在一个类中的3个线程。
TBluetooth = class
private
FBTReceiveThread: TBTReceiveThread;
FBTSendThread: TBTSendThread;
FBTMsgHandlerThread: TBTMsgHandlerThread;
FBluetoothManager: TBluetoothManager;
FServiceName: String;
FServiceGUID: String;
function ManagerConnected(): Boolean;
public
constructor create(const AServicename: STring; const aGuid: String; const AValue: TBluetoothOnMsgReady);
destructor Destroy(); override;
function ListPairedDevices: TBluetoothDeviceList;
function getDeviceFromAdress(const Aadress: String): TBluetoothDevice;
function sendMessage(const aData: STring; const aIdentifier: STring; const Aadress: String;
const HighPriority: Boolean): TGuid;
procedure startListening;
// procedure stopListening;
procedure SetBluetoothOnError(const AValue: TBluetoothOnError);
procedure SetBluetoothOnMSGReady(const AValue: TBluetoothOnMsgReady);
procedure SetBluetoothSendStatus(const AValue: TBLuetoothSendStatus);
property BluetoothOnMSGReady: TBluetoothOnMsgReady write SetBluetoothOnMSGReady;
property BluetoothOnError: TBluetoothOnError write SetBluetoothOnError;
property BluetoothSendStatus: TBLuetoothSendStatus write SetBluetoothSendStatus;
end;
一种用于发送消息,一种用于接收消息,一种用于组合消息的各个部分。
手动拆分消息,以更好地控制它们的发送时间,并在重新审视端轻松组合它们。 我正在将消息部分添加到队列中,并且“ sendthread”正在将它们一一发送。
procedure TBTSendThread.Execute;
var
msgToSend: TBtMsgRec;
msgHeader, statusstr: String;
fData: TBytes;
begin
inherited;
while not terminated do
try
if (FQueue.Count > 0) then
begin
TMonitor.Enter(FLock);
try
msgToSend := FQueue.First;
FQueue.Delete(0);
FSocket := msgToSend.targetDevice.CreateClientSocket(StringToGuid(FServiceGUID), True);
FSocket.Connect;
msgHeader := msgToSend.Identifier + '|' + GUIDToString(msgToSend.FGuid) + '|' + inttoStr(msgToSend.Length) +
'|' + inttoStr(msgToSend.part) + '/' + inttoStr(msgToSend.max) + '|';
fData := TEncoding.UTF8.GetBytes(msgHeader + msgToSend.Data);
FSocket.SendData(fData);
if (msgToSend.part = msgToSend.max) then
dec(fQueueCount);
if assigned(FGetSendStatus) then
Synchronize(
procedure
begin
FGetSendStatus(msgToSend.FGuid, msgToSend.Length, msgToSend.part, msgToSend.max, fQueueCount);
end);
Sleep(50);
finally
TMonitor.Exit(FLock);
FSocket.close;
end;
end;
except
on e: Exception do
begin
Synchronize(
procedure
begin
if assigned(FBLuetoothOnError) then
FBLuetoothOnError(e);
end);
end;
end;
end;
接收线程读取Socket的缓冲区,并将原始字符串传递给msghandler线程。
procedure TBTReceiveThread.Execute;
var
FSocket: TBluetoothSocket;
ok: Boolean;
LData: TBytes;
begin
inherited;
while not terminated do
try
FSocket := FServerSocket.Accept(500);
if FSocket <> nil then
begin
ok := True;
while ok do
try
LData := FSocket.ReceiveData;
if (Length(LData) > 0) and assigned(FMsgHandlerThread) then
FMsgHandlerThread.addRawMsg(TEncoding.UTF8.GetString(LData));
except
ok := false;
end;
SetLength(LData, 0);
//sleep(50);
end;
except
on e: Exception do
begin
Synchronize(
procedure
begin
if assigned(FBLuetoothOnError) then
FBLuetoothOnError(e);
end);
end;
end;
end;
MSGHandler线程获取原始字符串并将其组合成完整的消息。当它收到消息的最后一部分时,会将已完成的消息移交。
procedure TBTMsgHandlerThread.Execute();
var
msg: TBtMsgRec;
NewMsg: Boolean;
i: Integer;
begin
inherited;
while not terminated do
begin
if (FRawMsgList.Count > 0) then
begin
msg := parseMsg(FRawMsgList.First);
FRawMsgList.Delete(0);
NewMsg := True;
for i := 0 to FParsedMsgList.Count - 1 do
if (msg.FGuid = FParsedMsgList[i].FGuid) then
begin
NewMsg := false;
msg.Data := FParsedMsgList[i].Data + msg.Data;
FParsedMsgList.Delete(i);
if (msg.part = msg.max) then
Synchronize(
procedure
begin
if assigned(FBluetoothOnMsgReady) then
FBluetoothOnMsgReady(msg);
end)
else
FParsedMsgList.add(msg);
break;
end;
if NewMsg then
if msg.max = 1 then
Synchronize(
procedure
begin
if assigned(FBluetoothOnMsgReady) then
FBluetoothOnMsgReady(msg);
end)
else
FParsedMsgList.add(msg);
end;
end;
end;
发送(通过回调通知我有关发送消息的状态进行监视)和合并部分工作正常,但某些消息未达到其目标。我看不到模式,可惜没有错误消息。
我认为问题出在我对线程的使用上。我的理论是,接收方线程以某种方式错过了一些消息。 因此,我尝试提高接收线程的优先级,并更改线程的睡眠时间。即使我认为在线程中使用睡眠不是一个好主意。但这是我第一次使用线程,并且大多数用于蓝牙通信的代码示例都使用它。
procedure TBTMsgHandlerThread.addRawMsg(ARawMsg: String);
begin
Synchronize(
procedure
begin
FRawMsgList.add(ARawMsg);
end);
end;