-------------------------------------------------------------基础单元----start-----------------------------------------------------------------------------
{********************************************************************}
{* 单元名称:UntModBusBase基础单元 *}
{* 功能描述:管理 连接、接收、发送 *}
{* *}
{*新建:张金宝 20230320 *}
{* *}
{* *}
{* *}
{* *}
{* *}
{* *}
{* *}
{* *}
{********************************************************************}
unit UntModBusBase;
interface
uses
Winapi.Windows,System.SysUtils,Classes,Winsock2;
type
TModbusClient=class
private
//连接对象
FSocket: TSocket;
protected
public
//构造函数
constructor Create();
//销毁函数
destructor Destroy();override;
//连接设备
function ConnectDev(IP:string;Port:string;var sMsg:string):Boolean;
//发送数据
function SendBytes(SendBuff:TByteArray;SendLen:Integer;var SucessLen:Integer;var sMsg:string):Boolean;
//接收数据
function RecvBytes(var RecvBuff:TByteArray;var RecvLen:Integer;var sMsg:string):Boolean;
//断开连接
function DisConnDev(var sMsg:string):Boolean;
end;
implementation
{$REGION '构造函数'}
constructor TModbusClient.Create;
begin
inherited;
end;
{$ENDREGION}
{$REGION '销毁函数'}
destructor TModbusClient.Destroy;
begin
inherited;
end;
{$ENDREGION}
{$REGION '连接设备'}
//参数说明:IP IP地址
// Port 端口号
// sMsg 错误消息
//返回值 True 成功,False 失败
function TModbusClient.ConnectDev(IP:string;Port:string;var sMsg:string):Boolean;
var
WSAData:TWSAData;//套接字实现的信息
iResult:Integer;//函数返回值
sockaddr:TSockAddr;//连接地址
begin
Result:=False;
try
//通过进程启动 Winsock DLL 的使用
iResult:=WSAStartup(MAKEWORD(2,2),WSAData);
if (iResult<>NO_ERROR) then
begin
sMsg:=Format('WSAStartup function failed with error: %d',[iResult]);
Exit;
end;
//创建socket连接服务器
FSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (FSocket = INVALID_SOCKET) then
begin
sMsg:=Format('socket function failed with error: %d',[WSAGetLastError()]);
WSACleanup();
Exit;
end;
//设置连接地址 端口
TSockAddrIn(sockaddr).sin_family := AF_INET;
TSockAddrIn(sockaddr).sin_addr.S_addr := inet_addr(PAnsiChar(AnsiString(IP)));
TSockAddrIn(sockaddr).sin_port := htons(StrToInt(Port));
//连接服务
iResult:=connect(FSocket, sockaddr, SizeOf(TSockAddrIn));
if iResult=SOCKET_ERROR then
begin
sMsg:=Format('connect function failed with error: %d',[WSAGetLastError()]);
closesocket(FSocket);
WSACleanup();
Exit;
end;
sMsg:='OK';
Result:=True;
except
on e:Exception do
begin
sMsg:='ConnectDevException:'+e.Message;
end;
end;
end;
{$ENDREGION}
{$REGION '发送数据'}
//参数说明:SendBuff 发送的数据
// SendLen 缓冲区长度
// SucessLen 发送成功的数据长度
// sMsg 错误消息
//返回值 True 成功,False 失败
function TModbusClient.SendBytes(SendBuff:TByteArray;SendLen:Integer;var SucessLen:Integer;var sMsg:string):Boolean;
var
iResult:Integer;//函数返回值
//调用方式标志
//MSG_DONTROUTE:指定数据不应受到路由的约束。 Windows 套接字服务提供程序可以选择忽略此标志。
//MSG_OOB仅) (流式套接字(例如SOCK_STREAM)发送 OOB 数据。
flags:Integer;
begin
Result:=False;
try
SucessLen:=0;
flags:=0;
//发送数据
iResult:=send(FSocket,SendBuff,SendLen,flags);
if iResult = SOCKET_ERROR then
begin
sMsg:=Format('send failed with error: %d',[WSAGetLastError()]);
Exit;
end;
SucessLen:=iResult;
sMsg:='OK';
Result:=True;
except
on e:Exception do
begin
sMsg:='SendBytesException:'+e.Message;
end;
end;
end;
{$ENDREGION}
{$REGION '接收数据'}
//参数说明:RecvBuff 接收到的数据
// RecvLen 接收到的数据长度
// sMsg 错误消息
//返回值 True 成功,False 失败
function TModbusClient.RecvBytes(var RecvBuff:TByteArray;var RecvLen:Integer;var sMsg:string):Boolean;
var
iResult:Integer;//函数返回值
//调用方式标志
//MSG_PEEK 查看传入数据。 数据将复制到缓冲区中,但不会从输入队列中删除。
//MSG_OOB 处理带外 (OOB) 数据。
//MSG_WAITALL 仅当发生以下事件之一时,接收请求才会完成:
//调用方提供的缓冲区已完全满。
//该连接已关闭。
//请求已被取消或出错。
//请注意,如果基础传输不支持MSG_WAITALL,或者套接字处于非阻塞模式,则此调用将失败并出现 WSAEOPNOTSUPP。 此外,如果指定了MSG_WAITALL以及MSG_OOB、MSG_PEEK或MSG_PARTIAL,则此调用将失败并出现 WSAEOPNOTSUPP。 数据报套接字或面向消息的套接字不支持此标志。
flags:Integer;
begin
Result:=False;
try
RecvLen:=4096;//默认4096
flags:=0;
repeat
//接收数据
iResult:=recv(FSocket, RecvBuff[0], RecvLen, flags);
until not iResult<=0;
if iResult<0 then
begin
sMsg:=Format('recv failed: %d',[WSAGetLastError()]);
Exit;
end;
RecvLen:=iResult;
sMsg:='OK';
Result:=True;
except
on e:Exception do
begin
sMsg:='RecvBytesException:'+e.Message;
end;
end;
end;
{$ENDREGION}
{$REGION '断开连接'}
//参数说明:
// sMsg 错误消息
//返回值 True 成功,False 失败
function TModbusClient.DisConnDev(var sMsg:string):Boolean;
var
iResult:Integer;//函数返回值
begin
Result:=False;
try
iResult:=closesocket(FSocket);
if iResult=SOCKET_ERROR then
begin
sMsg:=Format('closesocket function failed with error: %d',[WSAGetLastError()]);
WSACleanup();
Exit;
end;
//函数终止使用 Winsock 2 DLL
WSACleanup();
sMsg:='OK';
Result:=True;
except
on e:Exception do
begin
sMsg:='DisConnDevException:'+e.Message;
end;
end;
end;
{$ENDREGION}
end.
-------------------------------------------------------------基础单元----end-----------------------------------------------------------------------------
-------------------------------------------------------------使用-----start---------------------------------------------------------------------------------
mClient:TModbusClient;
mClient:=TModbusClient.Create;
//连接
procedure TModBusTestForm.ConnectButtonClick(Sender: TObject);
var
bRet:Boolean;//返回值
sMsg:string;//错误信息
begin
try
bRet:=mClient.ConnectDev(IPEdit.Text,PortEdit.Text,sMsg);
if bRet then
begin
StatusBar.Panels[0].Text:='连接成功';
end
else
begin
StatusBar.Panels[0].Text:='连接失败:'+sMsg;
end;
except
on e:Exception do
begin
ShowMessage('连接异常:'+e.Message);
end;
end;
end;
//断开
procedure TModBusTestForm.DisConnButtonClick(Sender: TObject);
var
bRet:Boolean;//返回值
sMsg:string;//错误信息
begin
try
bRet:=mClient.DisConnDev(sMsg);
if bRet then
begin
StatusBar.Panels[0].Text:='断开成功';
end
else
begin
StatusBar.Panels[0].Text:='断开失败:'+sMsg;
end;
except
on e:Exception do
begin
ShowMessage('断开异常:'+e.Message);
end;
end;
end;
//发送
procedure TModBusTestForm.SendButtonClick(Sender: TObject);
var
bRet:Boolean;//返回值
sMsg:string;//错误信息
SendBuff:TByteArray;//发送的报文
SendLen:Integer;//发送的报文长度
SucessLen:Integer;//发送成功的报文长度
addr:Integer;//地址
iValue:Integer;//发送的数据
RecvBuff:TByteArray;//返回的报文
RecvLen:Integer;//返回报文长度
sRet:string;//返回值
begin
try
addr:=StrToInt(SendAddrEdit.Text);
iValue:=StrToInt(SendValueEdit.Text);
SendLen:=12;
SendBuff[0] := $03;//事务处理标识符高位 客户机发起 用户定义
SendBuff[1] := $13;//事务处理标识符低位
SendBuff[2] := $00;//协议标识符高位 固定0X0000
SendBuff[3] := $00;//协议标识符低位 固定0X0000
SendBuff[4] := $00;//长度 高位
SendBuff[5] := $06;//长度 低位
SendBuff[6] := $01;//单元标识符 客户机发起 用户定义
SendBuff[7] := $06;//功能码 写入单个0x06 写入多个0x10 读取0x03
SendBuff[8] := Hi(addr);//寄存器地址高位
SendBuff[9] := Lo(addr);//寄存器地址低位
SendBuff[10] := Hi(iValue);//寄存器值 高位
SendBuff[11] := Lo(iValue);//寄存器值 低位
//sRet:=TEncoding.UTF8.GetString(SendBuff);
//sRet:=BytesToBase64(SendBuff);
bRet:=mClient.SendBytes(SendBuff,SendLen,SucessLen,sMsg);
if bRet then
begin
StatusBar.Panels[0].Text:='发送成功,报文长度:'+IntToStr(SucessLen);
//获取发送返回的报文
bRet:=mClient.RecvBytes(RecvBuff,RecvLen,sMsg);
if bRet then
begin
//返回报文转16进制
bRet:=BytesToStr(RecvBuff,RecvLen,sRet,sMsg);
if bRet then
begin
SendRetMemo.Text:=sRet;
end
else
begin
SendRetMemo.Text:='返回值转换失败:'+sMsg;
end;
end
else
begin
SendRetMemo.Text:='返回值接收失败:'+sMsg;
end;
end
else
begin
StatusBar.Panels[0].Text:='发送失败:'+sMsg;
end;
except
on e:Exception do
begin
ShowMessage('发送异常:'+e.Message);
end;
end;
end;
//接收
procedure TModBusTestForm.RecvButtonClick(Sender: TObject);
var
bRet:Boolean;//返回值
sMsg:string;//错误信息
addr:Integer;//地址
iRecvCount:Integer;//发送的数据
SendBuff:TByteArray;//发送的报文
SendLen:Integer;//发送的报文长度
SucessLen:Integer;//发送成功的报文长度
RecvBuff:TByteArray;//返回的报文
RecvLen:Integer;//返回报文长度
sRet:string;//返回值
begin
try
addr:=StrToInt(RecvAddrEdit.Text);
iRecvCount:=StrToInt(RecvCountEdit.Text);
SendLen:=12;
SendBuff[0] := $00;//事务处理标识符高位 用户定义
SendBuff[1] := $00;//事务处理标识符低位 用户定义
SendBuff[2] := $00;//协议标识符高位 固定0X0000
SendBuff[3] := $00;//协议标识符低位 固定0X0000
SendBuff[4] := $00;//长度 高位
SendBuff[5] := $06;//长度 低位
SendBuff[6] := $01;//单元标识符客户机发起 用户定义
SendBuff[7] := $03;//功能码 写入单个0x06 写入多个0x10 读取0x03
SendBuff[8] := Hi(addr);//起始地址高位
SendBuff[9] := Lo(addr);//起始地址低位
SendBuff[10] := Hi(iRecvCount);//寄存器数量高位
SendBuff[11] := Lo(iRecvCount);//寄存器数量低位
bRet:=mClient.SendBytes(SendBuff,SendLen,SucessLen,sMsg);
if bRet then
begin
//获取发送返回的报文
bRet:=mClient.RecvBytes(RecvBuff,RecvLen,sMsg);
if bRet then
begin
//返回报文转16进制
bRet:=BytesToStr(RecvBuff,RecvLen,sRet,sMsg);
if bRet then
begin
RecvMemo.Text:=sRet;
//返回值格式说明
//1 事务处理标识符 Hi
//1 事务处理标识符 Lo
//2 协议标识符号
//2 长度
//1 单元标识符
//1 功能码,读寄存器
//1 字节个数
//数据节点
end
else
begin
RecvMemo.Text:='返回值转换失败:'+sMsg;
end;
end
else
begin
RecvMemo.Text:='返回值接收失败:'+sMsg;
end;
end
else
begin
StatusBar.Panels[0].Text:='接收发送失败:'+sMsg;
end;
except
on e:Exception do
begin
ShowMessage('接收异常:'+e.Message);
end;
end;
end;
-------------------------------------------------------------使用-----end---------------------------------------------------------------------------------
标签:SendBuff,begin,end,delphi,通信,sMsg,modbus,var,Integer From: https://www.cnblogs.com/530263009QQ/p/17413175.html