// FO9-UDP.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#include
#include
#pragma comment(lib,"WS2_32")
int sd; /* Socket Discripter */
struct sockaddr_in my;
struct sockaddr_in dst;
struct sockaddr_in from;
#define MY_IP 0xC0A8010A // 自身的IP 地址:192.168.001.010
#define MY_PORT 10010 // 自身的端口编号
#define DST_IP 0xC0A80106 // 对方的IP 地址:192.168.001.006
#define DST_PORT 10020 // 对方的端口编号
unsigned char sbuf[2048];
unsigned char rbuf[2048];
// 存在于218TCP.C 中
void main_udp(void);
extern void mk_cmd_data(void);
extern int chk_rsp_data(int);
// 读取扩展MEMOBUS 协议、保持寄存器的内容(SFC=09),制作命令
void mk_cmd_data(void)
{
// 218 标题部的制作
// 数据类型设定
sbuf[0] = 0x11;// 扩展MEMOBUS (指令命令)
// 串行编号设定(每次发送时增加)
sbuf[1] = 0x00;
// 设定发送目标的通道编号
sbuf[2] = 0x00; // PLC 侧通道不固定,因此可固定为0
// 设定发送目标的通道编号
sbuf[3] = 0x00; // 因电脑中无通道概念,固定为0。
sbuf[4] = 0x00; // 备用
sbuf[5] = 0x00; // 备用
// 所有数据数设定(从218 标题的首部到MEMOBUS 数据的最后)
sbuf[6] = 0x16; // L (22 字节=218 标题(12 字节)+ MEMOBUS 数据(10 字节))
sbuf[7] = 0x00; // H
sbuf[8] = 0x00;// 备用
sbuf[9] = 0x00;// 备用
sbuf[10] = 0x00;// 备用
sbuf[11] = 0x00;// 备用
// MEMOBUS 数据部的制作
// Length 为从MFC 开始到数据的最后
sbuf[12] = 0x08; // MEMOBUS 数据长度(L)
sbuf[13] = 0x00; // MEMOBUS 数据长度(H)
// MFC 固定为0x20
sbuf[14] = 0x20;
// SFC 为0x09 (读取保持寄存器的内容(扩展))
sbuf[15] = 0x09;
// CPU 编号设定
sbuf[16] = 0x10; // 对方为CPU1。多台时为1-4。自身的CPU 编号固定为0。
sbuf[17] = 0x00; // Spare 固定为0
// 参考编号设定
sbuf[18] = 0x00; // Adr(L) 首地址为MW0
sbuf[19] = 0x00; // Adr(H)
// 寄存器数设定
sbuf[20] = 0x0A; // DataNum(L) 从首地址读取10 字
sbuf[21] = 0x00; // DataNum(H)
}
// 响应数据的检查
int chk_rsp_data( int rlen )
{
int rc;
rc = 0;
// 所有数据长度的检查
if ( rlen != 40 )// 读取10 字对应的响应为40 字节
// (218 标题(12 字节)+MEMOBUS 数据(28 字节))
{
rc = -1;
return( rc );
}
// 数据包类型检查
if ( rbuf[0] != 0x19 )// 非MEMOBUS 响应
{
rc = -2;
return( rc );
}
// 串行编号检查
if (sbuf[1] != rbuf[1] )// 与命令的串行编号不一致
{
rc = -3;
return( rc );
}
// 传送文件中的所有数据长度的检查
if (( rbuf[6] != 0x28 ) &&(rbuf[7] !=0x00))// 40 字节= 218 标题(12 字节)+MEMOBUS 数据(28 字节)
{
rc = -4;
return( rc );
}
// MEMOBUS 数据长度检查
if (( rbuf[12] != 0x1A ) || (rbuf[13] != 0x00))// 26 字节
{
rc = -5;
return( rc );
}
// MFC 的检查
if ( rbuf[14] != 0x20 )// MFC 固定为0x20
{
rc = -6;
return( rc );
}
// SFC 的检查
if ( rbuf[15] != 0x09 )// SFC 为0x09 (读取保持寄存器的内容)
{
rc = -7;
return( rc );
}
// 寄存器数的检查
if (( rbuf[18] != 0x0A ) || (rbuf[19] != 0x00))// 非10 字
{
rc = -8;
return( rc );
}
// 读取寄存器数据rbuf[20] 以后
return( rc );
}
void main_udp(void)
{
WSADATA wsadata;
int rc, slen, rlen, fromlen;
// Winsock.dll 的使用声明(最初必需)
rc = WSAStartup( 0x0101, &wsadata );
if ( rc != 0 )
{
exit(0);
}
// sockaddr 构造体(IP 地址、端口编号等)的清零
memset( (char *)&my, 0, sizeof(struct sockaddr));
memset( (char *)&dst, 0, sizeof(struct sockaddr));
// 自身的IP 地址、端口编号的声明
my.sin_family = AF_INET;
my.sin_addr.s_addr = htonl( MY_IP );
my.sin_port = htons( MY_PORT );
// 对方的IP 地址、端口编号的声明
dst.sin_family = AF_INET;
dst.sin_addr.s_addr = htonl( DST_IP );
dst.sin_port = htons( DST_PORT );
// UDP 套接字的生成
sd = socket( AF_INET, SOCK_DGRAM, 0 );
if ( sd <= 0 )
{
printf( "Error: Socket !!\n" );
exit(0);
}
// 自局端口编号的捆绑配置
rc = bind( sd, ( struct sockaddr *)&my, sizeof(struct sockaddr_in));
if ( rc == -1 )
{
closesocket( sd );
printf( "Error: bind !!\n" );
exit(0);
}
// 分配自局端口编号后,制作指令数据。
mk_cmd_data();
// 反复执行发送命令和接收响应。
while(1)
{
// 发送命令数据
// 主控制器不能发送数据时,该处理不会结束。
slen = sendto( sd, reinterpret_cast(&sbuf[0]), 22, 0, (struct sockaddr *)&dst, sizeof(struct sockaddr));
// 发送命令(22 字节)
if ( slen != 22 )// 如果发送成功,则返回发送的字节数(22 字节)。
{
closesocket(sd);
printf( "Error: Send !! -> %d\n", slen );
exit(0);
}
// 接收响应数据
// 子控制器没有发送数据时,该处理不会结束。
fromlen = sizeof(struct sockaddr);
//将rbuf从无符号变量,转换为指针变量1-4字节
rlen = recvfrom( sd, reinterpret_cast(&rbuf[0]), sizeof(rbuf), 0, (struct sockaddr *)&from, &fromlen );
// 接收对方发送的数据
if ( rlen <= 0 )// 如果接收错误则返回0 以下
{
closesocket(sd);
printf( "Error: Recv !! -> %d\n", rlen );
exit(0);
}
// 响应数据的检查
rc = chk_rsp_data( rlen );
if ( rc != 0 )// 接收数据异常
{
closesocket(sd);
exit(0);
}
sbuf[1] ++;// 增加218 标题的串行编号
printf( "Hit Any Key !!\n" );
}
}
MSVCRTD.lib(crtexe.obj) : error LNK2019: 无法解析的外部符号 main,该符号在函数 __tmainCRTStartup 中被引用
已尝试修改项目预处理及系统配置属性,更改为CONSOLE,但是仍然报错?求解