使用zmq的多帧消息完成一个文件传输功能

zmq多帧消息

zmq可以发送多帧消息,也就是说一个消息可以包含多个帧,这么说可能不太好理解。举一个例子,比如要传输一个文件,如果文件很大,这时候把这个文件传输成一个消息,这个消息肯定会是很多次的传输,那么每一次传输的就是一帧。这就不用规定特殊的协议去传输文件了,所以用zmq传输文件就不用类似ftp那样复杂的文件传输协议了。

多帧消息

现在可以这么处理,比如发送一个多帧消息,这个消息有五个帧,可以把这五个帧封装成一个结构体处理,也可以这样做:

zmq_send (socket, &message, ZMQ_SNDMORE);
...
zmq_send (socket, &message, ZMQ_SNDMORE);
...
zmq_send (socket, &message, 0);

这样发送就是一个有五帧的多帧消息,你也可以发送更多。

当接收一个多帧消息的时候也是很简单的。

while (1) {
    zmq_msg_t message;
    zmq_msg_init (&message);
    zmq_recv (socket, &message, 0);
    // 处理一帧消息
    zmq_msg_close (&message);
    int64_t more;
    size_t more_size = sizeof (more);
    zmq_getsockopt (socket, ZMQ_RCVMORE, &more, &more_size);
    if (!more)
        break; // 已到达最后一帧
}

下面是一些注意点:

  • 发送端发送多帧消息的时候,只有最后一帧被提交,整个消息才会被发送出去,之前是存在内存中。

  • 使用zmq_poll()函数,接收端在接收第一帧的时候,其实整个消息已经都收到了。所以多帧消息是整体传输的。

  • 多帧消息每一帧其实就是一个zmq_msg结构对象。

  • 应该使用ZMQ_RECVMORE去判断是否还有消息了。

现在可以利用多帧消息做一个文件上传下载工具:

客户端file_send.cpp:

/***************************************************************
*文件传输的客户端
****************************************************************/
#include <zmq.hpp>
#include <string>
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>

#define FILE_FRAME_SIZE 1024


struct file_route_msg{
	unsigned int path_len;
	char path[255];
};

int read_file_frame(char* filename,int pos,char* buffer,int length)
{
	FILE* fp = fopen(filename,"rb");
	if (NULL == fp)
	{
		std::cout<<"fopen failed!"<<std::endl;
		return -1;
	}

	//调整文件指针
	fseek(fp,pos,SEEK_SET);
	int size = fread(buffer,1,length,fp);
	if(size != length)
	{
		std::cout << "read over!" << std::endl;
	}

	fclose(fp);
	return size;
}

int main(int argc, char const *argv[])
{
	//获取文件的路径
	if(argc != 2)
	{
		std::cout << "please input like this:" << argv[0] << " <filepath>"<<std::endl;
	}

	//判断文件是否存在
	if(0 != access(argv[1],R_OK))
	{
		std::cout<<"file is not exists,please check:"<<argv[1]<<std::endl;
		return -1;
	}
	//开始使用zmq
	zmq::context_t context(1);

	zmq::socket_t socket(context,ZMQ_PUSH);

	socket.setsockopt(ZMQ_SNDTIMEO,0);

	socket.connect("tcp://localhost:9000");


	//开始发送文件
	file_route_msg head;
	memset(head,0,sizeof(head));
	head.path_len = strlen(argv[1]);
	head.path_len = htonl(head.path_len);//转换成网络字节序
	memcpy(head.path_len,argv[1],head.path_len);


	
	//发送文件路径
	socket.send(&head.path_len,4,ZMQ_SNDMORE);
	socket.send(head.path,strlen(head.path),ZMQ_SNDMORE);

	int pos = 0;

	char buffer[FILE_FRAME_SIZE] = {0};
	while(1)
	{
		buffer[FILE_FRAME_SIZE] = {0};

		//从文件中读取一帧
		int size = read_file_frame(argv[1],pos,buffer,FILE_FRAME_SIZE);
		pos += size;

		if(size < 0)
		{
			std::cout << "read file failed!" << std::endl;
			socket.send(NULL,0,0);
			break;
		}
		else if(size == FILE_FRAME_SIZE)
		{//完整读取一帧
			zmq::message_t msg_frame(buffer,size);
			socket.send(msg_frame,ZMQ_SNDMORE);
		}
		else if(size < FILE_FRAME_SIZE)
		{
			std::cout << "reaf file content over" <<pos<<" bytes"<<std::endl;
			zmq::message_t msg_frame(buffer,size);
			socket.send(msg_frame,0);
			break;

		}

	}
	socket.close();
	content.close();


	return 0;
}

服务端:


总结:

使用zmq的多帧消息进行文件传输可以避免定义复杂的传输协议,真香。

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用ZMQ的PUB-SUB模式可以方便地实现广播消息的发送和接收。下面是一个示例代码,可以创建一个PyQt窗口并使用ZMQ PUB套接字广播消息: ```python import sys import zmq from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton class MyWindow(QMainWindow): def __init__(self): super().__init__() # 创建一个按钮,并在点击时发送广播消息 button = QPushButton("Send Broadcast Message", self) button.setGeometry(50, 50, 200, 50) button.clicked.connect(self.send_broadcast_message) # 设置窗口大小和标题 self.setGeometry(300, 300, 300, 150) self.setWindowTitle('ZMQ Demo') def send_broadcast_message(self): context = zmq.Context() socket = context.socket(zmq.PUB) socket.bind("tcp://*:5555") message = "Hello, World!" socket.send(message.encode()) if __name__ == '__main__': app = QApplication(sys.argv) window = MyWindow() window.show() sys.exit(app.exec_()) ``` 在这个示例中,我们创建了一个继承自QMainWindow的MyWindow类。在MyWindow的构造函数中,我们创建了一个按钮,并在点击时调用send_broadcast_message()方法发送广播消息。在send_broadcast_message()方法中,我们创建了一个ZMQ上下文和套接字,然后将套接字绑定到本地TCP端口5555。我们发送一个“Hello, World!”消息,这个消息会被所有订阅了这个端口的接收器接收到。 你需要在运行这段代码之前确认已经有至少一个ZMQ订阅器正在监听本地TCP端口5555。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值