【C/C++】TCP Demo传Image Raw Data

环境 Windows VS2019
调试只做了3次互传,且图像信息为虚拟的vector数据,仅做了实现,无校验和鲁棒性提升
host -> server:传输原始图像Image,以及图像属性的结构体
server->host:传输图像的覆盖数组

参考1
参考2

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端效果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值