最近做的项目,MFC作为server,PLC作为client,搞了两天,还是基础太差,先记录一下遇到的问题吧。
TCP、UDP测试软件:https://download.csdn.net/download/qq_38109843/11255416,可以测试一下通信是否正常。
自己写的通信和测试软件一样,接收PLC端显示“?”,估计PLC端发的不是char类型,可能是二进制、十六进制,也有可能是混合的(协议书里面有int、char、real等类型)。最后发现只能以十六进制接收,长度还不一样,通过观察做了一下调整,具体程序如下。
程序
声明线程:
CWinThread *thread_recv;
static UINT server_thd(void *param);
定义线程:
thread_recv = AfxBeginThread(server_thd, this, THREAD_PRIORITY_NORMAL, 0, 0, NULL);
UINT CGigeCameraDemoDlg::server_thd(void *param)
{
CString Coil_number;
CString Materia_width;
CString Lead_postion;
CString Running_Speed;
CString Telegram_designation;
CString Telegram_counter;
CString Telegram_length;
WSADATA wsaData;
WORD wVersion;
wVersion = MAKEWORD(2, 2);
WSAStartup(wVersion, &wsaData);
SOCKADDR_IN local_addr;
SOCKADDR_IN client_addr;
int iaddrSize = sizeof(SOCKADDR_IN);
int res;
char msg[1024];
CGigeCameraDemoDlg * dlg = (CGigeCameraDemoDlg *)AfxGetApp()->GetMainWnd();
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(28357);
local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if ((listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
dlg->update("创建监听失败");
}
if (bind(listen_sock, (struct sockaddr*) &local_addr, sizeof(SOCKADDR_IN)))
{
dlg->update("绑定错误");
}
listen(listen_sock, 1);
if ((sock = accept(listen_sock, (struct sockaddr *)&client_addr, &iaddrSize)) == INVALID_SOCKET)
{
dlg->update("accept 失败");
}
else
{
CString port;
port.Format(_T("%d"), int(ntohs(client_addr.sin_port)));
dlg->update("已连接来自:" + CString(inet_ntoa(client_addr.sin_addr)) + " 端口:" +
port);
}
接收数据
while (1)
{
if ((res = recv(sock, msg, 1024, 0)) == -1)
{
dlg->update("失去连接");
break;
}
else
{
//msg[res] = '\0';
CString msg1;
CString msg_all;
for (int i = 0; i < res; i++)
{
msg1.Format(_T("%X"), msg[i]); //转16进制读取
int length = msg1.GetLength();
if (length > 2)
{
msg1 = msg1.Right(2);
}
else
{
if (length < 2) {
msg1 = "0" + msg1;
}
}
msg_all += msg1;
}
//dlg->update(msg_all);
Telegram_designation = msg_all.Mid(0, 8);
Telegram_counter = msg_all.Mid(8, 8);
Telegram_length = msg_all.Mid(16, 8);
Coil_number = msg_all.Mid(24, 24);
Materia_width = msg_all.Mid(48, 8);
Lead_postion = msg_all.Mid(56, 8);
Running_Speed = msg_all.Mid(64, 8);
dlg->update("卷号:" + Coil_number + " 来料宽度:" + Materia_width + " 焊接头:" + Lead_postion + " 速度:" + Running_Speed);
int td = HEXTOTEN(Telegram_designation);
int tc = HEXTOTEN(Telegram_counter);
int tl = HEXTOTEN(Telegram_length);
//std::cout << td << " " << tc << " " << tl << " ";
CString coil_all="";
for (int i = 0;i < 12; i++)
{
CString tmp = Coil_number.Mid(2*i, 2);
int cn = HEXTOTEN(tmp);
CString cn1;
cn1.Format(_T("%c"), cn);//第一步的变量
coil_all.Format(_T("%s%s"), coil_all, cn1);
//std::wcout << "coil_all" << coil_all.GetBuffer() << " ";
}
dlg->m_value1.SetWindowText(coil_all);
coil_number = coil_all;
USES_CONVERSION;
int mw = HEXTOTEN(Materia_width);
int lp = HEXTOTEN(Lead_postion);
int rs = HEXTOTEN(Running_Speed);
int a = 1557;
CString s;
s.Format(_T("%d"), mw);
dlg->m_value3.SetWindowText(s);
//int a =0x43160000; 下面两行代码来自于这个的灵感
//float b = *(float*)&a;
//printf("%f\n",b);
int n = strtol(T2A(Materia_width), NULL, 16);
float b = *(float*)&n;
}
}
return 0;
}
十六进制转换为int类型:转十进制
十六进制转char:转十进制再转ASCII
十六进制转real:其实是IEEE756标准32位浮点型运算,起初准备十六进制转unsigned int,然后转二进制,再转十进制,然后解码最后得到,代码在这里:http://www.bccn.net/paste/1695/,实在烦的不行,输入还要unsigned int,还要把十六进制转成unsigned int,烦的一比,最后放弃这个方法。
最后两句话就搞定了,在网上查了很多很多,终于摸索出来了。
转换代码
vector<bool> get_hex_2b(unsigned int a);
int get_hex_jiema(vector<bool> a);
float get_10dec(vector<bool> a);
int HEXTOTEN(CString s);
vector<bool> get_hex_2b(unsigned int a)//将十六进制转化成二进制
{
vector<bool> x;
for (int i = 0; i < 32; i++)
{
if ((((int)a)&(0x80000000 >> i)))
{
x.push_back(1);
}
else
{
x.push_back(0);
}
}
/打印十六进制的二进制码
//cout << "二进制码:" << endl;
//for_each(x.begin(), x.end(), fun);
//cout << endl;
///
return x;
}
int get_hex_jiema(vector<bool> a)//参数为短浮点数的二进制码
{
//将原来的二进制码的1-8位装到移码容器中
vector<bool> yima(a.begin() + 1, a.begin() + 9);
vector<bool>::iterator ite = yima.begin();//设置容器的迭代器
unsigned int sum = 0;
//计算二进制代码表示的十进制数
for (int i = 0; i < 8; i++)
{
sum = sum + (*ite)*pow(2, 7 - i);
ite++;
}
int jiema = sum - 127;
return jiema;
}
float get_10dec(vector<bool> a)//参数为短浮点数的二进制码
{
//存整数部分的二进制 ,初始值中有一个1,为尾码的隐含位
vector<bool> zhengshu(1, 1);
vector<bool> xiaoshu;//存小数部分的二进制
//将原本的二进制代码的9-尾位装到尾码容器中
vector<bool> weima(a.begin() + 9, a.end());
//根据阶码大小,向左移位尾码,得到整数的二进制代码
zhengshu.insert(zhengshu.end(), weima.begin(), weima.begin() + get_hex_jiema(a));
//尾码的剩余部分为小数的二进制代码
xiaoshu.insert(xiaoshu.end(), weima.begin() + get_hex_jiema(a), weima.end());
//
//打印整数和小数部分的二进制码
//cout << "整数部分:" << endl;
//for_each(zhengshu.begin(), zhengshu.end(), fun);
//cout << endl;
//cout << "小数部分:" << endl;
//for_each(xiaoshu.begin(), xiaoshu.end(), fun);
//cout << endl;
/
float zheng_shu = 0;
float xiao_shu = 0;
float sum = 0;
//计算整数的十进制大小
for (int i = zhengshu.size(); i > 0; i--)
{
zheng_shu = zheng_shu + zhengshu[i - 1] * pow(2, zhengshu.size() - i);
}
//计算小数的十进制大小
for (int i = 0; i < xiaoshu.size(); i++)
{
xiao_shu = xiao_shu + xiaoshu[i] * pow(2, -(i + 1));
}
sum = zheng_shu + xiao_shu;
//判断符号位
if (a[0] == 1)
sum = 0 - sum;
return sum;
}
int HEXTOTEN(CString s)
{
USES_CONVERSION;
//LPWSTR ss1 = T2A(s);
int i = 0, sum;
string sz2 = T2CA((LPCTSTR)s);
//string sz2 =s.GetBuffer();
int count123 = sz2.length();
sum = 0;
for (i = count123 - 1; i >= 0; i--)//从十六进制个位开始,每位都转换成十进制
{
if (sz2[i] >= '0'&&sz2[i] <= '9')//数字字符的转换
{
sum += (sz2[i] - 48)*pow(16, count123 - i - 1);
}
else if (sz2[i] >= 'A'&&sz2[i] <= 'F')//字母字符的转换
{
sum += (sz2[i] - 55)*pow(16, count123 - i - 1);
}
}
return(sum);
//cout << sum;
}