window下使用tcp传输视频(c++)
Posted 日暮乡关何处是
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了window下使用tcp传输视频(c++)相关的知识,希望对你有一定的参考价值。
参考链接:
网络编程:基于TCP的socket网络传输视频(C++, python)
由于项目要求,需要使用tcp完成视频的传输,udp其实也可以,但是udp不可靠,怕丢帧。
菜鸟一个,边缝边写,希望抛砖引玉,大家有意见可以评论区见。哈哈哈!
tcp相关内容不再赘述,本人也是半吊子,会用,远离之前学过,有点忘记了。干货开始:
vs完整工程文件(包括代码和可执行文件):
文件较大,建议csdn下载
csdn:0积分下载,无需梯子
github:需要梯子,文件超过100m了,只上传了源码
整体思路
- 对于视频文件读入之后按帧传输,每一帧传输之前使用opencv进行压缩(接收端接收到数据之后也需要解压缩)。
- 在传输压缩后的图像数据之前,先传输视频的总帧数和单帧压缩后数组的长度,从而帮助接收端进行解码。
- 服务器端和客户端都可实现收发操作。
环境配置
win10
opencv4.5.1
c++ 11
vs2019
废话不多说,直接上代码:
服务器端:
server.h
#pragma once
#include<iostream>
#include<winsock.h>
#include <string>
#pragma comment(lib,"ws2_32.lib")
#include "myopencv.h"
using namespace std;
class Server
public:
int m_port; //端口号
//定义服务端套接字,接受请求套接字
SOCKET m_server;
SOCKET m_accept;
VideoCapture m_cap;
vector<Mat> m_file_in;
vector<Mat> m_file_out;
string m_send_buf;
string m_recv_buf;
bool initialization(const int& port, const VideoCapture& cap); // 初始化
bool build_connect();
bool send_data();
bool receive_data();
bool free_connect();
;
server.cpp
#include "server.h"
#define SIZE 100
bool Server::initialization(const int& port, const VideoCapture& cap)
m_port = port;
m_cap = cap;
// 初始化库(windows独有)
//初始化套接字库
WORD w_req = MAKEWORD(2, 2);//版本号
WSADATA wsadata;
int err;
err = WSAStartup(w_req, &wsadata);
if (err != 0)
cout << "初始化套接字库失败!" << endl;
return false;
else
cout << "初始化套接字库成功!" << endl;
//检测版本号
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2)
cout << "套接字库版本号不符!" << endl;
WSACleanup();
return false;
else
cout << "套接字库版本正确!" << endl;
return true;
bool Server::build_connect()
//服务端地址客户端地址
SOCKADDR_IN server_addr;
SOCKADDR_IN accept_addr;
//填充服务端信息
server_addr.sin_family = AF_INET; // 用来定义那种地址族,AF_INET:IPV4
server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 保存ip地址,htonl将一个无符号长整型转换为TCP/IP协议网络的大端
// INADDR_ANY表示一个服务器上的所有网卡
server_addr.sin_port = htons(m_port); // 端口号
//创建套接字
m_server = socket(AF_INET, SOCK_STREAM, 0); // 使用tcp进行连接
if (::bind(m_server, (SOCKADDR*)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR)
cout << "套接字绑定失败!" << endl;
WSACleanup();
return false;
else
cout << "套接字绑定成功!" << endl;
//设置套接字为监听状态
if (listen(m_server, SOMAXCONN) < 0)
cout << "设置监听状态失败!" << endl;
WSACleanup();
return false;
else
cout << "设置监听状态成功!" << endl;
cout << "服务端正在监听连接,请稍候...." << endl;
//接受连接请求
int len = sizeof(SOCKADDR);
m_accept = accept(m_server, (SOCKADDR*)&accept_addr, &len);
if (m_accept == SOCKET_ERROR)
cout << "连接失败!" << endl;
WSACleanup();
return false;
cout << "连接建立,准备接受数据" << endl;
return true;
bool Server::send_data()
Mat frame;
vector<uchar> data_encode;
std::vector<int> params; // 压缩参数
params.resize(3, 0);
params[0] = IMWRITE_JPEG_QUALITY; // 无损压缩
params[1] = 100;
char frames_cnt[10] = 0, ;
_itoa_s(int(m_cap.get(CAP_PROP_FRAME_COUNT)), frames_cnt, 10);
send(m_accept, frames_cnt, 10, 0);
cout << "开始发送" << endl;
int j = 0;
while (m_cap.read(frame))
m_file_in.push_back(frame.clone());
imencode(".jpg", frame, data_encode, params); // 对图像进行压缩
int len_encoder = data_encode.size();
_itoa_s(len_encoder, frames_cnt, 10);
send(m_accept, frames_cnt, 10, 0);
_itoa_s(SIZE, frames_cnt, 10);
send(m_accept, frames_cnt, 10, 0);
// 发送
char send_char[SIZE] = 0, ;
int index = 0;
bool flag = false;
for (int i = 0; i < len_encoder / SIZE + 1; ++i)
for (int k = 0; k < SIZE; ++k)
if (index >= data_encode.size())
flag = true;
break;
send_char[k] = data_encode[index++];
send(m_accept, send_char, SIZE, 0);
//m_send_buf = to_string(j + 1);
//send(m_server, m_send_buf.c_str(), strlen(frames_cnt.c_str()), 0);
//waitKey(25);
//imshow("input", frame);
data_encode.clear();
++j;
cout << j << endl; // 发送端一直在发送
cout << "发送完成";
return true;
bool Server::receive_data()
Mat frame;
vector<uchar> data_decode;
std::vector<int> params; // 压缩参数
char recv_char[100];
params.resize(3, 0);
params[0] = IMWRITE_JPEG_QUALITY; // 无损压缩
params[1] = 100;
char frams_cnt[10] = 0, ;
recv(m_accept, frams_cnt, 10, 0);
// 解析总帧数
int count = atoi(frams_cnt);
for (unsigned int i = 0; i < count; ++i)
recv(m_accept, frams_cnt, 10, 0);
// 解析总帧数
int cnt = atoi(frams_cnt);
recv(m_accept, frams_cnt, 10, 0);
int size = atoi(frams_cnt);
data_decode.resize(cnt);
int index = 0;
bool flag = true;
for (int i = 0; i < cnt / size + 1; ++i)
recv(m_accept, recv_char, size, 0);
for (int k = 0; k < size; ++k)
if (index >= cnt)
flag = true;
break;
data_decode[index++] = recv_char[k];
//data_decode.pop_back();
frame = imdecode(data_decode, IMREAD_COLOR);
m_file_out.push_back(frame.clone());
//waitKey(25);
//imshow("s", frame);
//char recv_buf[50];
//recv(m_accept, recv_char, 50, 0);
//cout << "客户端信息:" << recv_buf << endl;
data_decode.clear();
cout << "接受完成";
return true;
bool Server::free_connect()
m_cap.release();
//关闭套接字
closesocket(m_server);
closesocket(m_accept);
//释放DLL资源
WSACleanup();
return true;
客户端
client.h
#pragma once
#include<iostream>
#include<winsock.h>
#include <string>
#pragma comment(lib,"ws2_32.lib")
#include "myopencv.h"
using namespace std;
class Server
public:
int m_port; //端口号
string m_ip; //服务端ip地址
//定义服务端套接字,接受请求套接字
SOCKET m_server;
VideoCapture m_cap;
vector<Mat> m_file_in;
vector<Mat> m_file_out;
//定义发送缓冲区和接受缓冲区
string m_send_buf;
string m_recv_buf;
bool initialization(const int& port, const string& ip, const VideoCapture& cap); // 初始化
bool build_connect();
bool send_data();
bool receive_data();
bool free_connect();
;
client.cpp
#include "client.h"
#define SIZE 100
bool Server::initialization(const int& port, const string& ip, const VideoCapture& cap)
m_port = port;
m_cap = cap;
m_ip = ip;
// 初始化库(windows独有)
//初始化套接字库
WORD w_req = MAKEWORD(2, 2);//版本号
WSADATA wsadata;
int err;
err = WSAStartup(w_req, &wsadata);
if (err != 0)
cout << "初始化套接字库失败!" << endl;
return false;
else
cout << "初始化套接字库成功!" << endl;
//检测版本号
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2)
cout << "套接字库版本号不符!" << endl;
WSACleanup();
return false;
else
cout << "套接字库版本正确!" << endl;
return true;
bool Server::build_connect()
//服务端地址客户端地址
SOCKADDR_IN server_addr;
SOCKADDR_IN accept_addr;
//填充服务端信息
server_addr.sin_family = AF_INET; // 用来定义那种地址族,AF_INET:IPV4
server_addr.sin_addr.S_un.S_addr = inet_addr(m_ip.c_str()); // 保存ip地址,htonl将一个无符号长整型转换为TCP/IP协议网络的大端
// INADDR_ANY表示一个服务器上的所有网卡
server_addr.sin_port = htons(m_port); // 端口号
//创建套接字
m_server = socket(AF_INET, SOCK_STREAM, 0);
if (connect(m_server, (SOCKADDR*)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR)
cout << "服务器连接失败!" << endl;
WSACleanup();
return false;
else
cout << "服务器连接成功!" << endl;
return true;
bool Server::send_data()
Mat frame;
vector<uchar> data_encode;
std::vector<int> params; // 压缩参数
params.resize(3, 0);
params[0] = IMWRITE_JPEG_QUALITY; // 无损压缩
params[1] = 100;
char frames_cnt[10] = 0, ;
_itoa_s(int(m_cap.get(CAP_PROP_FRAME_COUNT)), frames_cnt, 10);
send(m_server, frames_cnt, 10, 0);
cout << "开始发送" << endl;
int j = 0;
while (m_cap.read(frame))
m_file_in.push_back(frame.clone());
imencode(".jpg", frame, data_encode, params); // 对图像进行压缩
int len_encoder = data_encode.size();
_itoa_s(len_encoder, frames_cnt, 10);
send(m_server, frames_cnt, 10, 0);
_itoa_s(SIZE, frames_cnt, 10);
send(m_server, frames_cnt, 10, 0);
// 发送
char send_char[SIZE] = 0, ;
int index = 0;
bool flag = false;
for (int i = 0; i < len_encoder / SIZE + 1; ++i)
for (int k = 0; k < SIZE; ++k)
if (index >= data_encode.size())
flag = true;
break;
send_char[k] = data_encode[index++];
send(m_server, send_char, SIZE, 0);
//m_send_buf = to_string(j + 1);
//send(m_server, m_send_buf.c_str(), strlen(frames_cnt.c_str()), 0);
//waitKey(25);
//imshow("input", frame);
data_encode.clear();
++j;
cout << j << endl; // 发送端一直在发送
cout << "发送完成";
return true;
bool Server::receive_data()
Mat frame;
vector<uchar> data_decode;
std::vector<int> params; // 压缩参数
char recv_char[100];
params.resize(3, 0);
params[0] = IMWRITE_JPEG_QUALITY; // 无损压缩
params[1] = 100;
char frams_cnt[10] = 0, ;
recv(m_server, frams_cnt, 10, 0);
// 解析总帧数
int count = atoi(frams_cnt);
for (unsigned int i = 0; i < count; ++i)
recv(m_server, frams_cnt, 10, 0);
// 解析总帧数
int cnt = atoi(frams_cnt);
recv(m_server, frams_cnt, 10, 0);
int size = atoi(frams_cnt);
data_decode.resize(cnt);
int index = 0;
bool flag = true;
for (int i = 0; i < cnt / size + 1; ++i)
recv(m_server, recv_char, size, 0);
for (int k = 0; k < size; ++k)
if (index >= cnt)
flag = true;
break;
data_decode[index++] = recv_char[k];
//data_decode.pop_back();
frame = imdecode(data_decode, IMREAD_COLOR);
m_file_out.push_back(frame.clone());
//waitKey(25);
//imshow("s", frame);
//char recv_buf[50];
//recv(m_accept, recv_char, 50, 0);
//cout << "客户端信息:" << recv_buf << endl;
data_decode.clear();
cout << "接受完成";
return true;
bool Server::free_connect()
m_cap.release();
//关闭套接字
closesocket(m_server);
//释放DLL资源
WSACleanup();
return true;
c++ && OpenCV的多线程实时视频传输(TCP on Windows)
项目场景:
在无线局域网里采用TCP协议传输海康威视网络视频:
上一篇文章中采用UDP协议传输网络视频,由于事先不知道图像字节长度,导致每次传输视频之前都需要根据图像大小更改UDP接收缓冲区,同时,上一篇文章中涉及到的只是在局域网中传输USB摄像头视频,如何快速解码网络摄像头并且高质量传输。这里我用到了多线程对快速解码这一要求进行了响应,采用TCP协议,在传输图像字节之前,先传输图像字节长度,在接收端根据发送端发送的长度信息,实时new一个字节数组作为缓冲区对图像字节数据进行保存。
问题描述
1、服务器端从接收缓冲区接收图像字节时,将图像队列复制给字节数组,如果采用在循环中进行赋值,那么当队列长度很大时 , 耗时很长,请看代码:
以下为未优化之前的代码
char send_char[SIZE] = 0, ;
int index = 0;
bool flag = false;
for (int i = 0; i < len_encoder / SIZE + 1; ++i)
for (int k = 0; k < SIZE; ++k)
if (index >= data_encode.size())
flag = true;
break;
send_char[k] = data_encode[index++];
send(m_server, send_char, SIZE, 0);
原因分析:
在循环中将data_encode队列中的每一个元素赋值为
send_char,如果这个循环很大,是很耗时的.
解决方案:
memcpy函数的功能是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中。
memcpy是内存拷贝,当一段连续的空间很长时,采用内存拷贝效率高,而采用在循环中对数组元素进行单个赋值 效率很低。采用memcpy拷贝时 是一次性将源src 拷贝到目标dst
以下为优化后的代码
char *send_b = new char[data_encode.size()];
memcpy(send_b, &data_encode[0], data_encode.size());
优化后 , 代码的执行速度比优化前至少加快了10倍
问题描述
2、采用opencv软解码海康威视摄像头视频流时,如果解码速度太慢,这样的状态持续一段时间后,会导致解码模块出bug,报类似于以下错误:
[h264 @ 000000000ef76940] cabac decode of qscale diff failed at 84 17 [h264 @ 000000000ef76940] error while decoding MB 84 17, bytestream 507ffmpeg
原因分析:
这种错误,我在网上查了一下,是由于解码模块在相邻两帧解码速度太慢导致的错误
之前代码逻辑是在一个线程里 解码视频 + 发送视频 ,这个过程太耗时,超过了40ms,久而久之,码流得不到解析,就会报错
解决方案:
那么这里可以采用多线程:一个线程解码视频,一个线程发送视频
以下为未优化之前的代码
while (m_cap.read(frame))
imencode(".jpg", frame, data_encode, params); // 对图像进行压缩
int len_encoder = data_encode.size();
_itoa_s(len_encoder, frames_cnt, 10);
send(m_server, frames_cnt, 10, 0);
_itoa_s(SIZE, frames_cnt, 10);
send(m_server, frames_cnt, 10, 0);
// 发送
char send_char[SIZE] = 0, ;
int index = 0;
bool flag = false;
char *send_b = new char[data_encode.size()];
for (int i = 0; i<data_encode.size(); i++)
//data_encode.size()数据装换成字符数组
send_b[i] = data_encode[i];
int iSend = send(m_server, send_b, data_encode.size(), 0);
delete[]send_b;
data_encode.clear();
++j;
以下为优化后的代码
myMutex.lock();
if (queueInput.empty()) //如果队列中没有数据 说明队列为空 此时应该等待生产者向队列中输入数据
myMutex.unlock();//释放锁
Sleep(3);//睡眠三秒钟 把锁让给生产者
continue;
else
frame = queueInput.front();//从队列中取出图像矩阵
queueInput.pop();
myMutex.unlock();//释放锁
imencode(".jpg", frame, data_encode, params); // 对图像进行压缩
int len_encoder = data_encode.size();//获取图像编码后的字节长度 方便后续通过TCP传输时 接收端知道此次传输的字节大小
_itoa_s(len_encoder, frames_cnt, 10);//
send(m_server, frames_cnt, 10, 0);//将图像字节长度 进行传输
// 发送
int index = 0;//标志实时接收图像字节的长度 方便程序中判断还有多少字节尚未接收到
char *send_b = new char[data_encode.size()];// 创建一个字节数组 开启大小为图像字节长度的字符数组空间
//这里是将data_encode首地址且长度为图片字节长度 通过内存拷贝复制到send_b数组中,相比于采用循环单个元素赋值,速度快了至少10倍
memcpy(send_b, &data_encode[0], data_encode.size());
int iSend = send(m_server, send_b, data_encode.size(), 0);//将图像字节数据传输到服务器端
delete[]send_b;//销毁对象
data_encode.clear();//将队列清空 方便下一次进行图像矩阵接收
++j;
优化后 , 代码的执行速度比优化前至少加快了10倍
问题描述
3、在局域网中进行数据传输时,假如客户端传输100个字节长度的数据,在服务器端可能是先接收到53个字节,然后再接收剩下的47个字节的数据。如果我把客户端和服务器端都放在一个终端上运行,则不会出现这种情况。由于前期是在一个终端(也就是客户端和服务器端都在一台终端上)上面进行代码开发,代码没有出现问题,但是将代码移植到局域网中,出现了上述所说的现象:
原因分析:
这种现象,可能是由于网络传输导致。既然不能避免,那么在服务器端接收数据时,就进行数据长度校验,客户端首先会向服务器发送一个待接收的数据长度值,服务器端按照这个长度值进行数据接收
解决方案:
在服务器端接收数据时,就进行数据长度校验,客户端首先会向服务器发送一个待接收的数据长度值,服务器端按照这个长度值进行数据接收
以下为解决方案代码
while (count > 0)//这里只能写count > 0 如果写count >= 0 那么while循环会陷入一个死循环
//在网络通信中 recv 函数一次性接收到的字节数可能小于等于设定的SIZE大小,这时可能需要多次recv
int iRet = recv(m_accept, recv_char, count, 0);
int tmp = 0;//用来保存当前接收的数据长度
for (int k = 0; k < iRet; k++)
tmp = k+1;
index++;
if (index >= cnt) break;
memcpy(&data_decode[index - tmp ], recv_char , tmp);//内存拷贝函数
if (!iRet) return -1;
count -= iRet;//更新余下需要从接收缓冲区接收的字节数量
delete[]recv_char;
下面贴出客户端代码
// tcp_video_client.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "stdafx.h"
#include "opencv2\\opencv.hpp"
#include "opencv2\\imgproc\\imgproc.hpp"
#include<WinSock2.h>
#include<iostream>
#include<mutex>
#include<thread>
#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"opencv_world340.lib")
std::mutex myMutex;
std::queue<cv::Mat> queueInput;//存储图像的队列
void get_online_video()
//海康威视子码流拉流地址 用户名 admin 密码abc.1234 需要修改为对应的用户名和密码
std::string url = "rtsp://admin:abc.1234@192.168.0.64:554/h264/ch1/sub/av_stream";
cv::VideoCapture cap(url);
cv::Mat frame;//保存抽帧的图像矩阵
while (1)
cap >> frame;
myMutex.lock();
if (queueInput.size() > 3)
queueInput.pop();
else
queueInput.push(frame);
myMutex.unlock();
int send_online_video()
WORD w_req = MAKEWORD(2, 2);//版本号
WSADATA wsadata;
int err;
err = WSAStartup(w_req, &wsadata);
if (err != 0)
std::cout << "初始化套接字库失败!" << std::endl;
return false;
else
std::cout << "初始化套接字库成功!" << std::endl;
//检测版本号
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2)
std::cout << "套接字库版本号不符!" << std::endl;
WSACleanup();
return false;
else
std::cout << "套接字库版本正确!" << std::endl;
SOCKADDR_IN server_addr;
SOCKADDR_IN accept_addr;
//填充服务端信息
server_addr.sin_family = AF_INET; // 用来定义那种地址族,AF_INET:IPV4
std::string m_ip = "192.168.0.111";
server_addr.sin_addr.S_un.S_addr = inet_addr(m_ip.c_str()); // 保存ip地址,htonl将一个无符号长整型转换为TCP/IP协议网络的大端
// INADDR_ANY表示一个服务器上的所有网卡
server_addr.sin_port = htons(7777); // 端口号
//创建套接字
SOCKET m_server = socket(AF_INET, SOCK_STREAM, 0);
if (connect(m_server, (SOCKADDR*)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR)
std::cout << "服务器连接失败!" << std::endl;
WSACleanup();
return false;
else
std::cout << "服务器连接成功!" << std::endl;
cv::Mat frame;
std::vector<uchar> data_encode;//保存从网络传输数据解码后的数据
std::vector<int> params; // 压缩参数
params.resize(3, 0);
params[0] = cv::IMWRITE_JPEG_QUALITY; // 无损压缩
params[1] = 30;//压缩的质量参数 该值越大 压缩后的图像质量越好
char frames_cnt[10] = 0, ;
std::cout << "开始发送" << std::endl;
int j = 0;
while (1)
/* 这里采用多线程 从队列中存取数据 主要是防止单线程解码网络视频速度太慢导致的网络拥塞*/
myMutex.lock();
if (queueInput.empty()) //如果队列中没有数据 说明队列为空 此时应该等待生产者向队列中输入数据
myMutex.unlock();//释放锁
Sleep(3);//睡眠三秒钟 把锁让给生产者
continue;
else
frame = queueInput.front();//从队列中取出图像矩阵
queueInput.pop();
myMutex.unlock();//释放锁
imencode(".jpg", frame, data_encode, params); // 对图像进行压缩
int len_encoder = data_encode.size();//获取图像编码后的字节长度 方便后续通过TCP传输时 接收端知道此次传输的字节大小
_itoa_s(len_encoder, frames_cnt, 10);//
send(m_server, frames_cnt, 10, 0);//将图像字节长度 进行传输
// 发送
int index = 0;//标志实时接收图像字节的长度 方便程序中判断还有多少字节尚未接收到
char *send_b = new char[data_encode.size()];// 创建一个字节数组 开启大小为图像字节长度的字符数组空间
//这里是将data_encode首地址且长度为图片字节长度 通过内存拷贝复制到send_b数组中,相比于采用循环单个元素赋值,速度快了至少10倍
memcpy(send_b, &data_encode[0], data_encode.size());
int iSend = send(m_server, send_b, data_encode.size(), 0);//将图像字节数据传输到服务器端
delete[]send_b;//销毁对象
data_encode.clear();//将队列清空 方便下一次进行图像矩阵接收
++j;
std::cout << "发送完成";
closesocket(m_server);//关闭发送端套接字
WSACleanup();//释放初始化Ws2_32.dll所分配的资源。
int main()
std::thread Get(get_online_video);
std::thread Send(send_online_video);
Get.join();
Send.join();
return 0;
下面贴出服务器端代码
bool Server::receive_data()
Mat frame;
vector<uchar> data_decode;
std::vector<int> params; // 压缩参数
params.resize(3, 0);
params[0] = IMWRITE_JPEG_QUALITY; // 无损压缩
params[1] = 50;
cv::namedWindow("Server", cv::WINDOW_NORMAL);
char frams_cnt[10] = 0, ;
// 解析总帧数
int count = atoi(frams_cnt);
int idx = 0;
while (1)
// 解析图片字节长度
int irecv = recv(m_accept, frams_cnt, 10, 0);
int cnt = atoi(frams_cnt);
data_decode.resize(cnt);//将队列大小重置为图片字节长度
int index = 0;//表示接收数据长度计量
count = cnt;//表示的是要从接收缓冲区接收字节的数量
char *recv_char = new char[cnt];//新建一个字节数组 数组长度为图片字节长度
while (count > 0)//这里只能写count > 0 如果写count >= 0 那么while循环会陷入一个死循环
//在网络通信中 recv 函数一次性接收到的字节数可能小于等于设定的SIZE大小,这时可能需要多次recv
int iRet = recv(m_accept, recv_char, count, 0);
int tmp = 0;
for (int k = 0; k < iRet; k++)
tmp = k+1;
index++;
if (index >= cnt) break;
memcpy(&data_decode[index - tmp ], recv_char , tmp);
if (!iRet) return -1;
count -= iRet;//更新余下需要从接收缓冲区接收的字节数量
delete[]recv_char;
try
frame = cv::imdecode(data_decode, CV_LOAD_IMAGE_COLOR);
if (!frame.empty())
imshow("Server", frame);
waitKey(1);
data_decode.clear();
else
std::cout << "#################################### " << std::endl;
data_decode.clear();
continue;
catch (const char *msg)
data_decode.clear();
continue;
cout << "接受完成";
return true;
以上为客户端和服务器端核心代码
完成代码可见github链接
https://github.com/linxizi/TCP_Online_Video.git
以上是关于window下使用tcp传输视频(c++)的主要内容,如果未能解决你的问题,请参考以下文章