由于实验平台的需求,需要实现在 VS 和 Matlab之间进行通信,传送实验数据。都是在本机上。
目标是:VS和Matlab之间互传Double类型的数据,VS是服务器端,Matlab是客户端。(VS2019 + Matlab2016)
C++这边Socket提供的接口提供函数只可以支持 char * 类型的指针(存疑,欢迎指正),所以想要传递double数据,首先需要进行一步类型转换,将 double 转化成 char 数组,Matlab接收到的是 浮点数的 ACSII 码值。
在这一步试了以下两种方法:
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
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;
}
接下来就是在C++这边写服务器端了,Socket编程的流程如下:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
#include //一般情况下,这个头文件位于windows.h之前,避免发生某些错误
#include
#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;
}
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] c++ Socket实现客户端与服务器数据传输
[2] socket编程
[3] MATLAB和C++程序使用TCP/IP协议进行通信