modbus-TCP 协议文档:
简单来说就是吧modbus RTU的报文做修改后使用TCP协议传输,通常modbus-TCP使用502端口。
报文格式在文档后部有了,写得很清楚,多了MBAP报头,去除了CRC校验,因为TCP协议已经可以保证报文的正确。
code如下,
#pragma once
#include <stdio.h>
#include<windows.h>
#pragma comment(lib, "Ws2_32.lib")
class M_Client
{
public:
//Constructor
M_Client(const char* Addr, int Port, int Id);
//连接
int Connect();
//发送TCP包
int SendMsg(const char* msg, int len);
//关闭
void Close();
//发送modbus包
void Modbus_sender_single(int Ref, int addr, int value);
private:
SOCKET m_sock;
int port;
const char* address;
int id;
};
#include "M_Client.h"
#include <errno.h>
M_Client::M_Client(const char* Addr, int Port, int Id)
{
address = Addr;
port = Port;
id = Id;
}
int M_Client::Connect()
{
int rlt = 0;
//用于记录错误信息并输出
int iErrMsg;
//启动WinSock
WSAData wsaData;
iErrMsg = WSAStartup(MAKEWORD(1, 1), &wsaData);
if (iErrMsg != NO_ERROR)
//有错误
{
printf("failed with wsaStartup error : %d\n", iErrMsg);
rlt = 1;
return rlt;
}
//创建Socket
m_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_sock == INVALID_SOCKET)
//创建Socket失败
{
printf("socket failed with error : %d\n", WSAGetLastError());
rlt = 2;
return rlt;
}
//目标服务器数据
sockaddr_in sockaddrServer;
sockaddrServer.sin_family = AF_INET;
sockaddrServer.sin_port = htons(port);
sockaddrServer.sin_addr.s_addr = inet_addr(address);
//连接,sock与目标服务器连接
iErrMsg = connect(m_sock, (sockaddr*)&sockaddrServer, sizeof(sockaddrServer));
if (iErrMsg < 0)
{
printf("connect failed with error : %d\n", iErrMsg);
printf("Error: %d\n", errno);
rlt = 3;
return rlt;
}
return rlt;
}
int M_Client::SendMsg(const char* msg, int len)
{
int rlt = 0;
int iErrMsg = 0;
//发送消息,指定sock发送消息
iErrMsg = send(m_sock, msg, len, 0);
if (iErrMsg < 0)
//发送失败
{
printf("send msg failed with error : %d\n", iErrMsg);
rlt = 1;
return rlt;
}
return rlt;
}
void M_Client::Close()
{
closesocket(m_sock);
}
void M_Client::Modbus_sender_single(int Ref, int addr, int value) //写一个寄存器,使用功能码16,修改后就可以写多个
{
unsigned char Temp_buf[20];
Temp_buf[0] = Ref;
Temp_buf[1] = 0;
Temp_buf[2] = 0;
Temp_buf[3] = 0;
Temp_buf[4] = 0;//从ID开始到最后的字节数
Temp_buf[5] = 9;
Temp_buf[6] = id;//从机ID
Temp_buf[7] = 16;//命令代码
Temp_buf[8] = (addr-1)/256;//addr head //开始的地址
Temp_buf[9] = (addr-1) % 256;
Temp_buf[10] = 0;//number of addr //地址的长度
Temp_buf[11] = 1;
Temp_buf[12] = 2;//# of Bytes for values //一共多少byte的值
Temp_buf[13] = value/256;//values //具体的值,这里我只改一个寄存器,就写一个值
Temp_buf[14] = value%256;
SendMsg((char*)Temp_buf, 15); //将报文发出,15为报文长度,这里是固定的
}
#include "M_Client.h"
using namespace std;
int main()
{
M_Client client("127.0.0.1",502,10); //连接本地回路,502端口,10号从机
client.Connect();
client.Modbus_sender_single(0, 145, 24323);// 将145号寄存器写为24323(十进制)
client.Close();
system("pause");
return 0;
}