Я пытаюсь написать небольшой Bluetooth-протокол для отправки сообщений в кодировке B64 с устройства Android на устройство Windows и наоборот.
Для этого я использую 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
Сообщение разбивается вручную для большего контроля над отправкой и для простого объединения их в конце восстановления.
Я добавляю части сообщения в очередь, и «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 Thread
Поток 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;
Краткое описание проблемы:
Отправка (отслеживается с помощью обратного вызова, который информирует меня о состоянии отправляемого сообщения) и объединяющая часть работает нормально, но некоторые сообщения не достигают своей цели. Я не могу видеть шаблон и, к сожалению, нет сообщений об ошибках.
Я думаю, что проблема заключается в моем использовании потоков. Моя теория состоит в том, что поток получателя так или иначе пропускает некоторые сообщения.
Поэтому я попытался повысить приоритет принимающего потока, а также изменить время ожидания потоков. Хотя я думаю, что это не очень хорошая идея использовать сон в потоках. Но я впервые работаю с потоками, и большинство примеров кода для связи по Bluetooth используют его.
Edit:
procedure TBTMsgHandlerThread.addRawMsg(ARawMsg: String);
begin
Synchronize(
procedure
begin
FRawMsgList.add(ARawMsg);
end);
end;