sockets - Indy TCP Socket 可以在两个线程之间共享吗?
问题描述
我想要一个连接,两个终端都等待读取命令,并且不时向另一个发送一些数据。当然,我知道如何实现我的协议,但如果我这样做,Socket.ReadUInt32
它会阻塞我的执行路径,并且我无法在需要时发送命令。所以我想,如果我使用同一个套接字从另一个线程发送命令怎么办?我写了一个最小的例子......它似乎正在工作。但我不确定这是否是正确的方法,或者这次只是运气......这种技术是线程安全的吗?额外的线程将使用套接字仅用于发送 UInt32 值,以唤醒另一端,然后连接将在主线程中进行。
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdTCPConnection,
IdTCPClient, IdBaseComponent, IdComponent, IdCustomTCPServer, IdTCPServer,
IdContext, IdThreadComponent;
const
WM_LOGEVENT = WM_USER + 1;
type
TForm1 = class(TForm)
Server: TIdTCPServer;
Client: TIdTCPClient;
BStartServer: TButton;
BConnectClient: TButton;
ClientWriteThread: TIdThreadComponent;
Memo: TMemo;
BSendCommand: TButton;
ClientReadThread: TIdThreadComponent;
procedure BStartServerClick(Sender: TObject);
procedure ServerExecute(AContext: TIdContext);
procedure BConnectClientClick(Sender: TObject);
procedure ClientWriteThreadRun(Sender: TIdThreadComponent);
procedure BSendCommandClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure ClientReadThreadRun(Sender: TIdThreadComponent);
private
procedure LogEvent(var Msg: TMessage); message WM_LOGEVENT;
procedure SendEvent(const Msg: String);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.LogEvent(var Msg: TMessage);
var PStr: PString;
begin
PStr:= PString(Msg.WParam);
Memo.Lines.Add(Copy(PStr^, 1, Length(PStr^)));
end;
procedure TForm1.SendEvent(const Msg: String);
begin
SendMessage(Handle, WM_LOGEVENT, WPARAM(@Msg), 0);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Server.Bindings.Clear;
Server.Bindings.Add.SetBinding('192.168.0.3', 60200);
Client.Host:= '192.168.0.3';
Client.Port:= 60200;
end;
procedure TForm1.BStartServerClick(Sender: TObject);
begin
Server.Active:= True;
Caption:= IntToStr(Byte(Server.Active));
end;
procedure TForm1.BConnectClientClick(Sender: TObject);
begin
Client.Connect;
ClientReadThread.Start;
end;
procedure TForm1.BSendCommandClick(Sender: TObject);
begin
ClientWriteThread.Start;
end;
procedure TForm1.ClientWriteThreadRun(Sender: TIdThreadComponent);
var Data: Cardinal;
begin
Data:= 1234;
SendEvent('Client send: '+ IntToStr(Data));
Client.Socket.Write(Data);
Sender.Terminate;
end;
procedure TForm1.ClientReadThreadRun(Sender: TIdThreadComponent);
var Data: Cardinal;
begin
SendEvent('Client listening...');
Data:= Client.Socket.ReadUInt32;
SendEvent('Client received: '+ IntToStr(Data));
Client.Disconnect;
SendEvent('Client stopped.');
Sender.Terminate;
end;
procedure TForm1.ServerExecute(AContext: TIdContext);
var Data: Cardinal;
Srv: String;
begin
Srv:= 'Server '+IntToStr(Random(100));
SendEvent(Srv+' listening...');
Data:= AContext.Connection.Socket.ReadUInt32;
SendEvent(Srv+' received: '+IntToStr(Data));
Data:= 9999;
SendEvent(Srv+' Send: '+IntToStr(Data));
AContext.Connection.Socket.Write(Data);
AContext.Connection.Disconnect;
SendEvent(Srv+' stopped.');
end;
end.
解决方案
是的,在一个线程中的连接上发送,同时在另一个线程中读取同一连接是安全的。套接字具有用于入站和出站数据的单独内部缓冲区。
只需确保您不要尝试同时从两个线程发送,或同时从两个线程读取,而不同步访问连接。
推荐阅读
- pascal - 周数计算
- java - 无法共享静态资源
- ios - 如何在 Swift iOS 上引用回调函数?
- c++ - SetWindowPos() 跨进程 DPI 感知
- php - 支付网关开发 - 处理和处理参数/密钥 PHP 到 Json,Json 到 PHP
- c++ - Qt Creator 链接器错误:LNK1104:无法打开 fil 'usb-1.0.lib' - Windows
- firebase - Firefox 不会在推送消息单击时在服务人员中打开 url
- c# - Xamarin Forms - 在 XAML 中使用等效的 TranslateTo
- html - 双击移动网站链接
- php - Mysqli 准备好的语句 - 数据未进入数据库(但给出成功消息)