Visual Studio C++与 Matlab 进行 TCP/IP 通信传送 double 类型数据

由于实验平台的需求,需要实现在 VS 和 Matlab之间进行通信,传送实验数据。都是在本机上。
目标是:VS和Matlab之间互传Double类型的数据,VS是服务器端,Matlab是客户端。(VS2019 + Matlab2016)

1.类型转换

C++这边Socket提供的接口提供函数只可以支持 char * 类型的指针(存疑,欢迎指正),所以想要传递double数据,首先需要进行一步类型转换,将 double 转化成 char 数组,Matlab接收到的是 浮点数的 ACSII 码值。
在这一步试了以下两种方法:

  • 利用C++提供的sprintf() 函数 ,将浮点数 传化成 char 数组,但是一次性传送多个数字的话,在传到 Matlab 之后,由于每个数的大小不一样,位数不一样,Matlab 不好分割,没办法处理。
  • 利用 union ,将double的八个字节塞给一个char数组,这样就可以保证每一次传送的位数是固定的 8位。union 内部的所有数据公用同一个地址,所以这一部分转换如下。
#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<iostream>
#include<string>
using namespace std;

const int len_double = sizeof(double);

typedef union doubletochar_8
{
	double num_double;
	char num_char[len_double];
}doubletochar;

int main()
{
	doubletochar num;
	char send_arr[len_double];
	double x = 10;
	num.num_double = x;
	for (int i = 0; i <= len_double-1;++i) //小端模式:低字节在低位,高字节在高地址
	{
		send_arr[i] = num.num_char[i];
		printf("%02x\n", send_arr[i]);
	}
	return 0;
}

2.sever端

接下来就是在C++这边写服务器端了,Socket编程的流程如下:

  1. 初始化
  2. 创建服务器的套接字 serviceSocket
  3. 绑定套接字,指定绑定的 IP地址 和 端口号 :将 socketAddr 与 serviceSocket 绑定
  4. 服务器监听
  5. 接受请求 :初始化一个接受的客户端socket—recvClientSocket
  6. 接收/发送数据 :recv//send 这两个函数都要操作 recvClientSocket。这两个函数返回值是成功发送的位数。socket中send和recv函数 一般改动的话也就是改这一部分,这篇讲得比较好。
  7. 关闭socket
  8. 终止
#define _WINSOCK_DEPRECATED_NO_WARNINGS 	
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>
#include<iostream>
#include<string>
#include<cstring>
#include<WS2tcpip.h>
#include <WinSock2.h>						//一般情况下,这个头文件位于windows.h之前,避免发生某些错误
#include<Windows.h>
#pragma comment(lib, "ws2_32.lib") 			//显示加载 ws2_32.dll	ws2_32.dll就是最新socket版本啦
using namespace std;
const int len_double = sizeof(double);
typedef union doubletochar_8
{
	double num_double;
	char num_char[len_double];
}doubletochar;

int main()
{
	cout << "-----------服务器-----------" << endl;
	const int BUF_SIZE = 4096;
	//	1	初始化
	WSADATA wsadata;
	WSAStartup(MAKEWORD(2, 2), &wsadata);	//make word,你把鼠标移到WSAStartup看看参数列表,是不是就是一个word啊


	//	2	创建服务器的套接字
	SOCKET serviceSocket;
	serviceSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);	//socket(协议族,socket数据传输方式,某个协议)	我们默认为0,其实就是一个宏
	if (SOCKET_ERROR == serviceSocket) {
		cout << "套接字闯创建失败!" << endl;
	}
	else {
		cout << "套接字创建成功!" << endl;
	}


	//	3	绑定套接字	指定绑定的IP地址和端口号
	sockaddr_in socketAddr;								//一个绑定地址:有IP地址,有端口号,有协议族
	socketAddr.sin_family = AF_INET;
	socketAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");		// IP
	socketAddr.sin_port = htons(5000); // 端口号
	int bRes = bind(serviceSocket, (SOCKADDR*)&socketAddr, sizeof(SOCKADDR));	//绑定注意的一点就是记得强制类型转换
	if (SOCKET_ERROR == bRes) {
		cout << "绑定失败!" << endl;
	}
	else {
		cout << "绑定成功!" << endl;
	}

	//	4	服务器监听	
	int lLen = listen(serviceSocket, 5);	//监听的第二个参数就是:能存放多少个客户端请求,到并发编程的时候很有用哦
	if (SOCKET_ERROR == lLen) {
		cout << "监听失败!" << endl;
	}
	else {
		cout << "监听成功!" << endl;
	}


	//	5	接受请求
	sockaddr_in revClientAddr;
	SOCKET recvClientSocket = INVALID_SOCKET;	//初始化一个接受的客户端socket
	int _revSize = sizeof(sockaddr_in);
	recvClientSocket = accept(serviceSocket, (SOCKADDR*)&revClientAddr, &_revSize);
	if (INVALID_SOCKET == recvClientSocket) {
		cout << "服务端接受请求失败!" << endl;
	}
	else {
		cout << "服务端接受请求成功!" << endl;
	}

	//	6	发送/接受 数据	
	char recvBuf[BUF_SIZE];
	int reLen = recv(recvClientSocket, recvBuf, strlen(recvBuf), 0);
	recvBuf[reLen] = '\0';
	if (SOCKET_ERROR == reLen) {
		cout << "服务端接收数据失败" << endl;
	}
	else {
		cout << "服务器接受到数据:    " << recvBuf << endl;
		//cout << typeid(recvBuf).name() << endl;
	}

	doubletochar num;
	int count = 0;
	while (count < 64)
	{
		double aa = count;
		char send_arr[len_double];
		num.num_double = aa;
		for (int i = len_double - 1; i >= 0; --i)//小端模式:低字节在低位,高字节在高地址
		{
			send_arr[len_double - 1 - i] = num.num_char[i];
		}
		int sLen = send(recvClientSocket, send_arr, sizeof(send_arr), 0);
		if (SOCKET_ERROR == sLen) {
			cout << "count is " << 1 + count << "服务端发送数据失败" << endl;
		}
		else
		{
			//cout << "服务端发送数据成功" << endl;
			cout << "count is "<<1 + count<<" num is "<<aa << endl;
		}
		count++;
	}
	//	7	关闭socket
	closesocket(recvClientSocket);
	closesocket(serviceSocket);

	//	8	终止
	WSACleanup();

	cout << "服务器停止" << endl;
	cin.get();
	return 0;
}

3. Client端

Matlab端作为客户端,由于传过来的是一堆 ACSII 码 (即 recv),所以先将这些码转换成 十六进制(dec2hex)的,然后横向展开,每十六位进行一次分割,然后再转换回 double (hex2num)。

clear
clc
close all
warning off all
%% 设置连接参数,要连接的地址为127.0.0.1(即本地主机),端口号为5000,作为客户机连接。
Client=tcpip('127.0.0.1',5000,'NetworkRole','client');
Client.BytesAvailable
%% 建立连接,建立完成后进行下一步,否则报错
fopen(Client);%与一个服务器建立连接,直到建立完成返回,否则报错。
sprintf('成功建立连接')
%% 发送字符串
sendtxt = 'hello hello';
fprintf(Client,sendtxt);
%% 接收字符串
Client.BytesAvailable
pause(1);
recv=fread(Client,Client.BytesAvailable,'char');
recv1 = dec2hex(recv);
recv2 = [];
for i = 1:length(recv1)
    recv2 = [recv2,recv1(i,:)]; %小端模式
end
count = 0;
recv3 = []; %转化成double
while count < length(recv1)/8
    recv3 = [recv3,hex2num(recv2(count*16+1:count*16+16))];
    count = count + 1;
end
%% 关闭客户端
fclose(Client);

注意事项

  1. Matlab默认的接收缓冲区是 512字节,所以如果matlab那边不做处理,C++那边一次最多传送64个数字。
  2. 先开启服务器端,然后开启客户端。
  3. 注意 IP 和 端口一致

参考博客:
[1] c++ Socket实现客户端与服务器数据传输
[2] socket编程
[3] MATLAB和C++程序使用TCP/IP协议进行通信

  • 7
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值