繁体   English   中英

如何通过 zmq 多部分消息发送文件?

[英]How to send a file by a zmq multipart message?

我正在尝试使用ZeroMQ基础设施发送视频,并将视频分成多个块进行发送。 当我这样做并将视频放入向量中以通过zmq::send_multipart发送它时,我得到了非常高的 RAM 内存使用率,因此后来我收到了分段错误错误。

我头疼的是,当我在发送多部分消息并运行程序的行上发表评论时,虽然对RAM内存的消耗没有那么大,但矢量制作正常并且我没有得到分段错误。

有人能给我一个关于如何发送这个文件的提示吗?

服务器代码:

#include <fstream>
#include <sstream>
#include <chrono>
#include <thread>
#include <iostream>
#include <future>
#include <zmq.hpp>
#include <zmq_addon.hpp>

using namespace std::chrono_literals;

const int size1MB = 1024 * 1024;

template <typename T>
void debug(T x)
{
  std::cout << x << std::endl;
}
//Generate new chunks
std::unique_ptr<std::ofstream> createChunkFile(std::vector<std::string> &vecFilenames)
{
  std::stringstream filename;
  filename << "chunk" << vecFilenames.size() << ".mp4";
  vecFilenames.push_back(filename.str());
  return std::make_unique<std::ofstream>(filename.str(), std::ios::trunc);
}
//Split the file into chunks
void split(std::istream &inStream, int nMegaBytesPerChunk, std::vector<std::string> &vecFilenames)
{

  std::unique_ptr<char[]> buffer(new char[size1MB]);
  int nCurrentMegaBytes = 0;

  std::unique_ptr<std::ostream> pOutStream = createChunkFile(vecFilenames);

  while (!inStream.eof())
  {
    inStream.read(buffer.get(), size1MB);
    pOutStream->write(buffer.get(), inStream.gcount());
    ++nCurrentMegaBytes;
    if (nCurrentMegaBytes >= nMegaBytesPerChunk)
    {
      pOutStream = createChunkFile(vecFilenames);
      nCurrentMegaBytes = 0;
    }
  }
}

int main()
{
  zmq::context_t context(1);
  zmq::socket_t socket(context, zmq::socket_type::rep);
  socket.bind("tcp://*:5555");
  std::ifstream img("video2.mp4", std::ifstream::in | std::ios::binary);
  std::ifstream aux;
  std::vector<std::string> vecFilenames;
  std::vector<zmq::const_buffer> data;
  std::ostringstream os;
  std::async(std::launch::async, [&img, &vecFilenames]() {
    split(img, 100, vecFilenames);
  });
  img.close();
  zmq::message_t message, aux2;
  socket.recv(message, zmq::recv_flags::none);
//Put the chunks into the vector
  std::async([&data, &aux, &os, &vecFilenames]() {
    for (int i = 0; i < vecFilenames.size(); i++)
    {
      std::async([&aux, &i]() {
        aux.open("chunk" + std::to_string(i) + ".mp4", std::ifstream::in | std::ios::binary);
      });
      os << aux.rdbuf();
      data.push_back(zmq::buffer(os.str()));
      os.clear();
      aux.close();
    }
  });
//Send the vector for the client
  std::async([&socket, &data] {
    zmq::send_multipart(socket, data);
  });
}

客户端:

#include <fstream>
#include <sstream>
#include <iostream>
#include <thread>
#include <chrono>
#include <string>
#include <zmq.hpp>
#include <zmq_addon.hpp>
#include <queue>
#include <deque>
#include <future>
#include <vector>

using namespace std::chrono_literals;

template <typename T>
void debug(T x)
{
  std::cout << x << std::endl;
}

int main()
{
  zmq::context_t context(1);
  zmq::socket_t socket(context, zmq::socket_type::req);
  socket.connect("tcp://localhost:5555");
  std::ofstream img("teste.mp4", std::ios::out | std::ios::binary);
  socket.send(zmq::buffer("ok\n"), zmq::send_flags::none);
  std::vector<zmq::message_t> send_msgs;
  zmq::message_t size;

  std::async([&send_msgs, &img, &socket] {
    zmq::recv_multipart(socket, std::back_inserter(send_msgs));
    while (send_msgs.size())
    {
      img << send_msgs[0].to_string();
      send_msgs.erase(send_msgs.begin());
    }
  });
}

尝试通过多部分消息移动所有数据确实将所有数据收集到一个巨大的 BLOB 中,再加上添加重复的 O/S 级传输类特定缓冲区,最可能的结果是崩溃。

将视频 BLOB 的各个块作为单独的简单消息有效负载发送并重建 BLOB(最好通过索引编号,可以选择重新请求未到达接收方的任何部分)。

使用带有REQ/REP std::async模式似乎有点棘手,因为这个原型必须保持其 .recv()-.send()-.recv()-.send()-...的 dFSA 交错序列...无止境……因为如果不这样做,就会陷入无法挽救的相互僵局。

对于流式视频(例如 CV / 场景检测),还有更多技巧可以使用 - 其中之一是使用ZMQ_CONFLATE选项,以便发送最近的视频帧,而不是在“过时”场景上浪费时间-images,这已经是历史的一部分,因此总是将最近的视频帧传送到接收端处理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM