环境 Windows VS2019
调试只做了3次互传,且图像信息为虚拟的vector数据,仅做了实现,无校验和鲁棒性提升
host -> server:传输原始图像Image,以及图像属性的结构体
server->host:传输图像的覆盖数组
Host端:TCPHost.h
#include <windows.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <vector>
//static const int IMAGE_BUFSIZE_720P = 100 * 10000; //常用于720P及以下,1280*720, 100-万像素
//static const int IMAGE_BUFSIZE_1080P = 220 * 10000; //常用于1K1080P,1920*1080, 207+万像素
//static const int IMAGE_BUFSIZE_1440P = 400 * 10000; //常用于2K1440P,2560*1440, 368+万像素
//static const int IMAGE_BUFSIZE_2160P = 900 * 10000; //常用于4K2160P,3840*2160/4096*2160, 829+/884+万像素
//static const int IMAGE_BUFSIZE_3112P = 1300 * 10000; //常用于4K3112P,4096*3112, 1274+万像素
struct DataPackageImage // 用于传给buff的连续地址定长结构体
{
int frameID;
int FPS;
int WIDTH;
int HEIGHT;
int VALIDLEN;
std::vector<float> m_ImageData;
};
struct DataPackageImageBuf // 用于传给buff的连续地址定长结构体
{
int frameID;
int FPS;
int WIDTH;
int HEIGHT;
int VALIDLEN;
float m_ImageData[10];
};
struct DataPackageMusk // 原始图像Musk结构体,用于篡改
{
int frameID;
int FPS;
int WIDTH;
int HEIGHT;
int VALIDLEN;
std::vector<int> vi_posX;
std::vector<int> vi_posY;
};
struct DataPackageMuskBuf // 用于传给buff的连续地址定长结构体
{
int frameID;
int FPS;
int WIDTH;
int HEIGHT;
int VALIDLEN;
int vi_posX[10]; // 连续定长地址,方便send、recv使用,需通过寻址的方式将vector转换过来
int vi_posY[10];
};
class TCPHost
{
public:
TCPHost();
const char IMAGE_HOST_IP[10] = "127.0.0.1";
const int IMAGE_HOST_PORT = 8888;
const int IMAGE_IMAGE_BUFSIZE = 1000000;
const int* transFps;
/*char* bufSendMusk = new char[IMAGE_BUFSIZE];
char* bufRecvMusk = new char[IMAGE_BUFSIZE];*/
char bufSendImage[128]; //长度应为sizeof(DataPackageMuskBuf)
char bufRecvMusk[128];
int sendData(DataPackageImage& dataPackageImage);
DataPackageMusk recvData();
~TCPHost();
private:
SOCKET _sock;
SOCKET _cSock;
int socketBuild();
};
Host端:TCPHost.cpp
#define WIN32_LEAN_AND_MEAN
//#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")//windows下调用动态库
#include <iostream>
#include "TCPHost.h"
using namespace std;
// 生成初始的图像数据
DataPackageImage getInitImage()
{
DataPackageImage resVar;
resVar.frameID = 0;
resVar.FPS = 30;
resVar.WIDTH = 18;
resVar.HEIGHT = 12;
resVar.VALIDLEN = 5;
float data = 0.0f;
for (int i = 0; i < resVar.VALIDLEN; i++)
{
resVar.m_ImageData.push_back(data);
data = data + 1.0f;
}
return resVar;
}
// TCPHost构造函数,初始化socket
TCPHost::TCPHost()
{
socketBuild();
}
// socket -> connect
int TCPHost::socketBuild()
{
//启动windows网络环境
WORD ver = MAKEWORD(2, 2);
WSADATA dat;
WSAStartup(ver, &dat);
//
//1.建立socket
_sock = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == _sock) {
printf("error, failed to build socket\n");
}
else {
printf("successfully build socket\n");
}
sockaddr_in _sin = {};
_sin.sin_family = AF_INET;
_sin.sin_port = htons(IMAGE_HOST_PORT);
inet_pton(AF_INET, IMAGE_HOST_IP, &_sin.sin_addr); //使用inet_pton替代inet_addr
//2.连接服务器
int connectRet = connect(_sock, (sockaddr*)&_sin, sizeof(sockaddr_in));
if (INVALID_SOCKET == connectRet) {
printf("连接失败\n");
}
else {
printf("连接成功\n");
}
return 0;
}
// send
int TCPHost::sendData(DataPackageImage& dataPackageImage)
{
// 打包buff数据
DataPackageImageBuf sendData;
sendData.frameID = dataPackageImage.frameID;
sendData.FPS = dataPackageImage.FPS;
sendData.WIDTH = dataPackageImage.WIDTH;
sendData.HEIGHT = dataPackageImage.HEIGHT;
sendData.VALIDLEN = dataPackageImage.VALIDLEN;
memcpy(&sendData.m_ImageData, &dataPackageImage.m_ImageData[0], sizeof(sendData.m_ImageData));
memcpy(&bufSendImage, &sendData, sizeof(DataPackageImageBuf));
send(_sock, bufSendImage, sizeof(DataPackageImageBuf), 0);
// 打印输出日志
std::cout << "【原始数据】dataPackageImage sizeof: " << sizeof(dataPackageImage) << endl;
std::cout << " -> frameID: " << dataPackageImage.frameID << endl;
std::cout << " -> FPS: " << dataPackageImage.FPS << endl;
std::cout << " -> WIDTH: " << dataPackageImage.WIDTH << endl;
std::cout << " -> HEIGHT: " << dataPackageImage.HEIGHT << endl;
std::cout << " -> VALIDLEN: " << dataPackageImage.VALIDLEN << endl;
std::cout << " -> m_ImageData [size] [data]: " << "[" << sizeof(dataPackageImage.m_ImageData) << "] [" <<
dataPackageImage.m_ImageData[0] << ", " << dataPackageImage.m_ImageData[1] << ", " <<
dataPackageImage.m_ImageData[2] << ", " << dataPackageImage.m_ImageData[3] << ", " <<
dataPackageImage.m_ImageData[4] << "]" << endl;
std::cout << "【发送数据】DataPackageImageBuf sizeof: " << sizeof(sendData) << endl;
std::cout << " -> frameID: " << sendData.frameID << endl;
std::cout << " -> FPS: " << sendData.FPS << endl;
std::cout << " -> WIDTH: " << sendData.WIDTH << endl;
std::cout << " -> HEIGHT: " << sendData.HEIGHT << endl;
std::cout << " -> VALIDLEN: " << sendData.VALIDLEN << endl;
std::cout << " -> m_ImageData [size] [data]: " << "[" << sizeof(sendData.m_ImageData) << "] [" <<
sendData.m_ImageData[0] << ", " << sendData.m_ImageData[1] << ", " <<
sendData.m_ImageData[2] << ", " << sendData.m_ImageData[3] << ", " << sendData.m_ImageData[4] << "]" << endl;
std::cout << "【发送数据】bufSendImage sizeof: " << sizeof(bufSendImage) << endl;
return 0;
}
// recv
DataPackageMusk TCPHost::recvData()
{
DataPackageMuskBuf recvData;
DataPackageMusk dataPackageMusk;
memset(bufRecvMusk, 0, sizeof(bufRecvMusk));
memset(&recvData, 0, sizeof(recvData));
int err_code = recv(_sock, bufRecvMusk, sizeof(bufRecvMusk), 0);
if (err_code > 0)
{
memcpy(&recvData, &bufRecvMusk, sizeof(DataPackageMuskBuf));
dataPackageMusk.frameID = recvData.frameID;
dataPackageMusk.FPS = recvData.FPS;
dataPackageMusk.WIDTH = recvData.WIDTH;
dataPackageMusk.HEIGHT = recvData.HEIGHT;
dataPackageMusk.VALIDLEN = recvData.VALIDLEN;
for (int i = 0; i < recvData.VALIDLEN; i++)
{
if (recvData.vi_posX[i] >= 0)
{
dataPackageMusk.vi_posX.push_back(recvData.vi_posX[i]);
dataPackageMusk.vi_posY.push_back(recvData.vi_posY[i]);
}
else
{
break;
}
}
// 打印日志
std::cout << "【接收数据】bufSendMusk sizeof: " << sizeof(bufRecvMusk) << endl;
std::cout << "【接收数据】DataPackageMuskBuf sizeof: " << sizeof(recvData) << endl;
std::cout << " -> frameID: " << recvData.frameID << endl;
std::cout << " -> FPS: " << recvData.FPS << endl;
std::cout << " -> WIDTH: " << recvData.WIDTH << endl;
std::cout << " -> HEIGHT: " << recvData.HEIGHT << endl;
std::cout << " -> VALIDLEN: " << recvData.VALIDLEN << endl;
std::cout << " -> vi_posX [size] [data]: " << "[" << sizeof(recvData.vi_posX) << "] ["
<< recvData.vi_posX[0] << ", " << recvData.vi_posX[1] << ", " << recvData.vi_posX[2] << ", " << recvData.vi_posX[3] << ", " << recvData.vi_posX[4] << "]" << endl;
std::cout << "【复原数据】dataPackageMusk sizeof: " << sizeof(dataPackageMusk) << endl;
std::cout << " -> frameID: " << dataPackageMusk.frameID << endl;
std::cout << " -> FPS: " << dataPackageMusk.FPS << endl;
std::cout << " -> WIDTH: " << dataPackageMusk.WIDTH << endl;
std::cout << " -> HEIGHT: " << dataPackageMusk.HEIGHT << endl;
std::cout << " -> VALIDLEN: " << dataPackageMusk.VALIDLEN << endl;
std::cout << " -> vi_posX [size] [data]: " << "[" << sizeof(dataPackageMusk.vi_posX) << "] ["
<< dataPackageMusk.vi_posX[0] << ", " << dataPackageMusk.vi_posX[1] << ", " << dataPackageMusk.vi_posX[2] << ", " << dataPackageMusk.vi_posX[3] << ", " << dataPackageMusk.vi_posX[4] << "]" << endl;
}
else
{
printf("客户端已退出\n");
}
return dataPackageMusk;
}
// TCPHost的析构函数,清除内存
TCPHost::~TCPHost()
{
closesocket(_sock);
WSACleanup();
std::cout << "TCP接口内存清除" << endl;
}
int main() {
// 获得初始图像数据
DataPackageImage dataPackageImage; // 发送数据声明
DataPackageMusk dataPackageMusk; // 接收数据声明
dataPackageImage = getInitImage(); // 构造函数:socket(_sock),connect
// 建立类
TCPHost imageHost;
// 数据交互
int frameID = 0;
char sendBuf[128] = {};
char recvBuf[128] = {};
for (int cycle = 0; cycle < 3; cycle++) {
imageHost.sendData(dataPackageImage);
Sleep(100);
dataPackageMusk = imageHost.recvData();
std::cout << "【ID】" << cycle << endl;
}
//7.关闭socket
printf("Client程序结束");
getchar();
system("pause");
return 0;
}
Server端:TCPServer.h
#include <windows.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <vector>
//static const int IMAGE_BUFSIZE_720P = 100 * 10000; //常用于720P及以下,1280*720, 100-万像素
//static const int IMAGE_BUFSIZE_1080P = 220 * 10000; //常用于1K1080P,1920*1080, 207+万像素
//static const int IMAGE_BUFSIZE_1440P = 400 * 10000; //常用于2K1440P,2560*1440, 368+万像素
//static const int IMAGE_BUFSIZE_2160P = 900 * 10000; //常用于4K2160P,3840*2160/4096*2160, 829+/884+万像素
//static const int IMAGE_BUFSIZE_3112P = 1300 * 10000; //常用于4K3112P,4096*3112, 1274+万像素
struct DataPackageImage // 用于传给buff的连续地址定长结构体
{
int frameID;
int FPS;
int WIDTH;
int HEIGHT;
int VALIDLEN;
std::vector<float> m_ImageData;
};
struct DataPackageImageBuf // 用于传给buff的连续地址定长结构体
{
int frameID;
int FPS;
int WIDTH;
int HEIGHT;
int VALIDLEN;
float m_ImageData[10];
};
struct DataPackageMusk // 原始图像Musk结构体,用于篡改
{
int frameID;
int FPS;
int WIDTH;
int HEIGHT;
int VALIDLEN;
std::vector<int> vi_posX;
std::vector<int> vi_posY;
};
struct DataPackageMuskBuf // 用于传给buff的连续地址定长结构体
{
int frameID;
int FPS;
int WIDTH;
int HEIGHT;
int VALIDLEN;
int vi_posX[10]; // 连续定长地址,方便send、recv使用,需通过寻址的方式将vector转换过来
int vi_posY[10];
};
class TCPServer
{
public:
TCPServer();
const char IMAGE_HOST_IP[10] = "127.0.0.1";
const int IMAGE_HOST_PORT = 8888;
const int IMAGE_IMAGE_BUFSIZE = 1000000;
const int* transFps;
/*char* bufSendMusk = new char[IMAGE_BUFSIZE];
char* bufRecvMusk = new char[IMAGE_BUFSIZE];*/
char bufSendMusk[128]; //长度应为sizeof(DataPackageMuskBuf)
char bufRecvImage[128];
int sendData(DataPackageMusk& dataPackageImage);
DataPackageImage recvData();
~TCPServer();
private:
SOCKET _sock;
SOCKET _cSock;
int socketBuild();
int socketListen();
};
Server端:TCPServer.cpp
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")//windows下调用动态库
#include <iostream>
#include "TCPServer.h"
using namespace std;
// 生成初始的图像数据
DataPackageMusk getInitMusk()
{
DataPackageMusk resVar;
resVar.frameID = 0;
resVar.FPS = 30;
resVar.WIDTH = 18;
resVar.HEIGHT = 12;
resVar.VALIDLEN = 5;
for (int i = 0; i < resVar.VALIDLEN; i++)
{
resVar.vi_posX.push_back(i);
resVar.vi_posY.push_back(i * 2);
}
return resVar;
}
// TCPHost构造函数,初始化socket
TCPServer::TCPServer()
{
socketBuild();
socketListen();
}
// socket->bind
int TCPServer::socketBuild()
{
WORD ver = MAKEWORD(2, 2);
WSADATA dat;
WSAStartup(ver, &dat);
_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in _sin = {};
_sin.sin_family = AF_INET;
_sin.sin_port = htons(IMAGE_HOST_PORT);
//_sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //INADDR_ANY默认地址
inet_pton(AF_INET, IMAGE_HOST_IP, &_sin.sin_addr); //使用inet_pton替代inet_addr
//2.bind绑定用于客户端连接的网络端口
if (SOCKET_ERROR == bind(_sock, (sockaddr*)&_sin, sizeof(_sin)))
{
printf("绑定失败\n");
}
else {
printf("绑定成功\n");
}
return 0;
}
// listen -> accept
int TCPServer::socketListen()
{
if (SOCKET_ERROR == listen(_sock, 5))
{
printf("监听失败\n");
}
else {
printf("监听成功\n");
}
//4.accept 等待连接
sockaddr_in clientAddr = {};
char IPdotdec[20];//存放点分十进制IP地址
int nAddrLen = sizeof(sockaddr_in);
_cSock = INVALID_SOCKET;
_cSock = accept(_sock, (sockaddr*)&clientAddr, &nAddrLen);
if (_cSock == INVALID_SOCKET)
{
printf("接收到无效客户端SOCKET\n");
}
else
{
printf("有客户端连接到服务器:Sock = %d,IP = %s \n", (int)_cSock, inet_ntop(AF_INET, &clientAddr.sin_addr, IPdotdec, 16));//使用inet_ntop替代ntoa
}
return 0;
}
// recv
DataPackageImage TCPServer::recvData()
{
DataPackageImageBuf recvData;
DataPackageImage dataPackageImage;
memset(bufRecvImage, 0, sizeof(bufRecvImage));
memset(&recvData, 0, sizeof(recvData));
int err_code = recv(_cSock, bufRecvImage, sizeof(bufRecvImage), 0);
if (err_code > 0)
{
memcpy(&recvData, &bufRecvImage, sizeof(DataPackageImageBuf));
dataPackageImage.frameID = recvData.frameID;
dataPackageImage.FPS = recvData.FPS;
dataPackageImage.WIDTH = recvData.WIDTH;
dataPackageImage.HEIGHT = recvData.HEIGHT;
dataPackageImage.VALIDLEN = recvData.VALIDLEN;
for (int i = 0; i < recvData.VALIDLEN; i++)
{
if (recvData.m_ImageData[i] >= 0)
{
dataPackageImage.m_ImageData.push_back(recvData.m_ImageData[i]);
}
else
{
break;
}
}
// 打印日志
std::cout << "【接收数据】bufRecvImage sizeof: " << sizeof(bufRecvImage) << endl;
std::cout << "【接收数据】DataPackageImageBuf sizeof: " << sizeof(recvData) << endl;
std::cout << " -> frameID: " << recvData.frameID << endl;
std::cout << " -> FPS: " << recvData.FPS << endl;
std::cout << " -> WIDTH: " << recvData.WIDTH << endl;
std::cout << " -> HEIGHT: " << recvData.HEIGHT << endl;
std::cout << " -> VALIDLEN: " << recvData.VALIDLEN << endl;
std::cout << " -> m_ImageData [size] [data]: " << "[" << sizeof(recvData.m_ImageData) << "] ["
<< recvData.m_ImageData[0] << ", " << recvData.m_ImageData[1] << ", " << recvData.m_ImageData[2] << ", " << recvData.m_ImageData[3] << ", " << recvData.m_ImageData[4] << "]" << endl;
std::cout << "【复原数据】dataPackageImage sizeof: " << sizeof(dataPackageImage) << endl;
std::cout << " -> frameID: " << dataPackageImage.frameID << endl;
std::cout << " -> FPS: " << dataPackageImage.FPS << endl;
std::cout << " -> WIDTH: " << dataPackageImage.WIDTH << endl;
std::cout << " -> HEIGHT: " << dataPackageImage.HEIGHT << endl;
std::cout << " -> VALIDLEN: " << dataPackageImage.VALIDLEN << endl;
std::cout << " -> m_ImageData [size] [data]: " << "[" << sizeof(dataPackageImage.m_ImageData) << "] ["
<< dataPackageImage.m_ImageData[0] << ", " << dataPackageImage.m_ImageData[1] << ", " << dataPackageImage.m_ImageData[2] << ", " << dataPackageImage.m_ImageData[3] << ", " << dataPackageImage.m_ImageData[4] << "]" << endl;
}
else
{
printf("客户端已退出\n");
}
return dataPackageImage;
}
// send
int TCPServer::sendData(DataPackageMusk& dataPackageMusk)
{
// 打包buff数据
DataPackageMuskBuf sendData;
sendData.frameID = dataPackageMusk.frameID;
sendData.FPS = dataPackageMusk.FPS;
sendData.WIDTH = dataPackageMusk.WIDTH;
sendData.HEIGHT = dataPackageMusk.HEIGHT;
sendData.VALIDLEN = dataPackageMusk.VALIDLEN;
memcpy(&sendData.vi_posX, &dataPackageMusk.vi_posX[0], sizeof(dataPackageMusk.vi_posX));
memcpy(&sendData.vi_posY, &dataPackageMusk.vi_posY[0], sizeof(dataPackageMusk.vi_posY));
memcpy(&bufSendMusk, &sendData, sizeof(DataPackageMuskBuf));
send(_cSock, bufSendMusk, sizeof(DataPackageMuskBuf), 0);
// 打印日志
std::cout << "【原始数据】dataPackageMusk sizeof: " << sizeof(dataPackageMusk) << endl;
std::cout << " -> frameID: " << dataPackageMusk.frameID << endl;
std::cout << " -> FPS: " << dataPackageMusk.FPS << endl;
std::cout << " -> WIDTH: " << dataPackageMusk.WIDTH << endl;
std::cout << " -> HEIGHT: " << dataPackageMusk.HEIGHT << endl;
std::cout << " -> VALIDLEN: " << dataPackageMusk.VALIDLEN << endl;
std::cout << " -> vi_posX [size] [data]: " << "[" << sizeof(dataPackageMusk.vi_posX) << "] ["
<< dataPackageMusk.vi_posX[0] << ", " << dataPackageMusk.vi_posX[1] << ", " << dataPackageMusk.vi_posX[2] << ", " << dataPackageMusk.vi_posX[3] << ", " << dataPackageMusk.vi_posX[4] << "]" << endl;
std::cout << "【发送数据】DataPackageMuskBuf sizeof: " << sizeof(sendData) << endl;
std::cout << " -> frameID: " << sendData.frameID << endl;
std::cout << " -> FPS: " << sendData.FPS << endl;
std::cout << " -> WIDTH: " << sendData.WIDTH << endl;
std::cout << " -> HEIGHT: " << sendData.HEIGHT << endl;
std::cout << " -> VALIDLEN: " << sendData.VALIDLEN << endl;
std::cout << " -> vi_posX [size] [data]: " << "[" << sizeof(sendData.vi_posX) << "] ["
<< sendData.vi_posX[0] << ", " << sendData.vi_posX[1] << ", " << sendData.vi_posX[2] << ", " << sendData.vi_posX[3] << ", " << sendData.vi_posX[4] << "]" << endl;
std::cout << "【发送数据】bufSendMusk sizeof: " << sizeof(bufSendMusk) << endl;
return 0;
}
// TCPHost的析构函数,清除内存
TCPServer::~TCPServer()
{
closesocket(_sock);
WSACleanup();
std::cout << "TCP接口内存清除" << endl;
}
int main() {
// 获得初始图像数据
DataPackageImage dataPackageImage; // 接收数据声明
DataPackageMusk dataPackageMusk; // 发送数据声明
dataPackageMusk = getInitMusk(); // 构造函数:socket(_sock),bind,listen(_cSock),accept
// 建立类
TCPServer imageServer;
// 数据交互
for (int cycle = 0; cycle < 3; cycle++) {
dataPackageImage = imageServer.recvData();
Sleep(100);
imageServer.sendData(dataPackageMusk);
std::cout << "【ID】" << cycle << endl;
}
//7.关闭socket
printf("Client程序结束");
getchar();
system("pause");
return 0;
}
实现效果Host端log:
实现效果Server端效果: