C++(MFC)和PLC使用TCP通信

最近做的项目,MFC作为server,PLC作为client,搞了两天,还是基础太差,先记录一下遇到的问题吧。
TCP、UDP测试软件:https://download.youkuaiyun.com/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;
}
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值