使用 zlib 库压缩多播数据包

compressing multicast packets with zlib library

我正在监听来自多播 ip 端口的数据包,并尝试使用 zlib 库压缩该数据包(想知道实时数据包中 zlib 的压缩率,因为这是我们客户的要求)。我已经实现了如下的 zlib 压缩代码,但是 outputDataBuffer 的长度打印不正确,我不知道我错过了什么。

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <zlib.h>

using namespace std;
struct sockaddr_in localSock;
struct ip_mreq group;
int maxpacketsize = 1500;

void connectSocket(int &sd,char *multicastIP,int multicastPort,char *interfaceIP);
void listenSocket(int &sd,const short &structureSize,const short &compressionType);
void compressZlib(char *inputDataBuffer,int inputDataLength,z_stream &defstream)

int main(int argc, char *argv[])
{
    int sd = 0;
    char multicastIP[16]="230.0.0.50";
    char interfaceIP[16]="192.168.225.132";
    int multicastPort = 13551;
    short structureSize = 0;
    connectSocket(sd,multicastIP,multicastPort,interfaceIP);
    listenSocket(sd,structureSize);
    return 0;
}

void connectSocket(int &sd,char *multicastIP,int multicastPort,char *interfaceIP)
{
    int reuse = 1;
    sd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sd < 0)
    {
        perror("Opening datagram socket error");
        exit(1);
    }
    printf("Opening datagram socket....OK.\n");
    if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
    {
        perror("Setting SO_REUSEADDR error");
        close(sd);
        exit(1);
    }
    printf("Setting SO_REUSEADDR...OK.\n");

    memset((char *) &localSock, 0, sizeof(localSock));
    localSock.sin_family = AF_INET;
    localSock.sin_port = htons(multicastPort);
    localSock.sin_addr.s_addr = INADDR_ANY;
    if(bind(sd, (struct sockaddr*)&localSock, sizeof(localSock)))
    {
        perror("Binding datagram socket error");
        close(sd);
        exit(1);
    }
    printf("Binding datagram socket...OK.\n");
    group.imr_multiaddr.s_addr = inet_addr(multicastIP);
    group.imr_interface.s_addr = inet_addr(interfaceIP);
    if(setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0)
    {
        perror("Adding multicast group error");
        close(sd);
        exit(1);
    }
    printf("Adding multicast group...OK.\n");
}

void compressZlib(char *inputDataBuffer,int inputDataLength,z_stream &defstream)
{

    char *outputDataBuffer = new char[inputDataLength];
    memset(outputDataBuffer,0,inputDataLength);
    defstream.avail_in = (uInt)strlen(inputDataBuffer)+1;
    defstream.next_in = (Bytef *)inputDataBuffer;
    defstream.avail_out = (uInt)sizeof(outputDataBuffer);
    defstream.next_out = (Bytef *)outputDataBuffer;

   if(deflate(&defstream, Z_FINISH) != Z_OK )
   {
       cout<<"Error"<<endl;
   }   
   //printf("%lu  %lu\n", inputDataLength,defstream.total_in);
   printf("%lu  %lu\n", inputDataLength,strlen(outputDataBuffer));
}

void listenSocket(int &sd,const short &structureSize)
{
    char databuf[5000] = "";
    int receivedBytes = 0;
    z_stream defstream;
    defstream.zalloc = Z_NULL ;
    defstream.zfree = Z_NULL;
    defstream.opaque = Z_NULL;
    deflateInit(&defstream, Z_FULL_FLUSH);
    while(1)
    {
        int socklen = sizeof(struct sockaddr_in);
        struct sockaddr_in saddr;
        receivedBytes = recvfrom(sd, databuf, maxpacketsize, 0, (struct sockaddr *)&saddr, (socklen_t*)&socklen);
        if(receivedBytes < 0)
        {
            perror("Reading datagram message error");
            close(sd);
            exit(1);
        }
        compressZlib(databuf,receivedBytes,defstream);
        //compressZlib(databuf1,strlen(databuf1));
        //compressZlib();
        //cout<<receivedBytes<<endl;

    }
    deflateEnd(&defstream);
}

我还使用了 compress2() 函数,如下所示:

compress2((unsigned char*)outputBuffer,&outputDataLength,(const unsigned char*)inputBuffer,(unsigned long)inputBufferLength,Z_DEFAULT_COMPRESSION);

但这也不起作用,outputDataLength 始终为 0。

Z_FINISH 调用 deflate() 意味着您正在或已经输入 deflate 最后的输入数据。 deflate 然后将终止流。一旦提供了足够的输出 space 来写入最后的压缩数据,这很可能是在第一次这样的调用中,deflate() 将 return Z_STREAM_END,而不是Z_OK。然后 deflate() 引擎完成并且不能再次使用,除非您先执行 deflateEnd() 后跟 deflateInit(),或者等效地更快地执行 deflateReset().

看来您缺少的是阅读文档所带来的回报。