qt tcp/udp socket 通信。 实现文字、图片、文件、语音和实时对讲。 包括客户端...

qt tcp/udp socket 通信。 实现文字、图片、文件、语音和实时对讲。 包括客户端和服务器端,带有报告,所有功能支持客户端和服务器端双向通信。 自己开发,非转卖! 虚拟物品可复制,联系不退,介意者勿拍。 需自行安装搭建,无! 开发环境:qt creator 5.11.3 操作系统:Windows,linux,麒麟都可以。 开发语言:c++ 具体功能如下: 1.tcpsocket/udpsocket连接与状态监听。 2.文字通信,tcp协议,有简单协议封装。 3.图片传输,tcp协议 处理:做了分包与粘包处理(可解决 TCP 粘包、Qtsocket readyread不触发或者只触发几次、数据丢失收不全数据问题); 同时做了客户端与服务器端的交互(类似握手); 做了简单协议封装。 4.语音传输(可理解为微信发的语音),tcp协议 处理:与图片传输一致;有简单协议封装; 点击语音播放按钮可播放,语音会覆盖之前的。 5.文件传输,tcp协议 处理:与图片传输一致,做了分包粘包和客户端/服务器端的交互; 有简单协议封装。 6.对讲功能(类似对讲机),udp协议,多线程实时对讲。

直接上干货吧,咱们聊聊怎么用Qt的TCP/UDP搞个全能通信工具。这玩意儿从文字到语音再到文件传输都得支持,客户端和服务端还要能互相撩,搞起来确实得注意不少坑点。

qt tcp/udp socket 通信。 实现文字、图片、文件、语音和实时对讲。 包括客户端和服务器端,带有报告,所有功能支持客户端和服务器端双向通信。 自己开发,非转卖! 虚拟物品可复制,联系不退,介意者勿拍。 需自行安装搭建,无! 开发环境:qt creator 5.11.3 操作系统:Windows,linux,麒麟都可以。 开发语言:c++ 具体功能如下: 1.tcpsocket/udpsocket连接与状态监听。 2.文字通信,tcp协议,有简单协议封装。 3.图片传输,tcp协议 处理:做了分包与粘包处理(可解决 TCP 粘包、Qtsocket readyread不触发或者只触发几次、数据丢失收不全数据问题); 同时做了客户端与服务器端的交互(类似握手); 做了简单协议封装。 4.语音传输(可理解为微信发的语音),tcp协议 处理:与图片传输一致;有简单协议封装; 点击语音播放按钮可播放,语音会覆盖之前的。 5.文件传输,tcp协议 处理:与图片传输一致,做了分包粘包和客户端/服务器端的交互; 有简单协议封装。 6.对讲功能(类似对讲机),udp协议,多线程实时对讲。

先说说底层连接这块。咱们直接继承QObject搞个NetworkCore类,里边塞两个成员:

QTcpSocket* tcpSocket;
QUdpSocket* udpSocket;

状态监听用信号槽就行,比如tcpSocket的状态变化信号:

connect(tcpSocket, &QTcpSocket::stateChanged, [](QAbstractSocket::SocketState state){
    qDebug() << "TCP状态变化:" << state;
});

文字通信得自己封装协议头。咱们搞个固定8字节的头部,前4字节存类型,后4字节存数据长度:

struct MsgHeader {
    quint32 type;  // 0文字 1图片 2文件 3语音
    quint32 length;
};

发消息的时候先序列化头部:

QByteArray sendData;
QDataStream stream(&sendData, QIODevice::WriteOnly);
stream.setVersion(QDataStream::Qt_5_11);
stream << header.type << header.length;
sendData.append(content);
tcpSocket->write(sendData);

收数据的时候有个大坑——readyRead可能只触发一次但数据没读完。咱们得搞个缓冲区:

void readPendingData() {
    while(tcpSocket->bytesAvailable() >= 8) { // 头部8字节
        QDataStream stream(tcpSocket);
        MsgHeader header;
        stream >> header.type >> header.length;
        
        // 检查是否收完整个包
        while(tcpSocket->bytesAvailable() < header.length) {
            if(!tcpSocket->waitForReadyRead(500)) {
                // 超时处理
                return;
            }
        }
        
        QByteArray payload;
        stream >> payload;
        handlePayload(header.type, payload);
    }
}

图片传输要特别注意分包。咱们在客户端先把图片转base64,拆成多个1024字节的包发送。每个包都带序号和总包数,服务端收到所有包后回个ACK确认。这个握手过程能有效避免丢包:

// 发送方
for(int i=0; i<totalPackets; i++){
    QByteArray packet;
    packet.append(QString::number(i).rightJustified(4, '0'));
    packet.append(imageData.mid(i*1024, 1024));
    sendPacket(packet);
    
    // 等ACK
    if(!waitForAck()){
        // 重传逻辑
    }
}

// 接收方
QMap<int, QByteArray> packetMap;
void processImagePacket(int seq, QByteArray data){
    packetMap.insert(seq, data);
    if(packetMap.size() == totalPackets){
        // 组装数据
        sendAck();
    }
}

实时对讲用UDP+多线程才够劲。开个单独线程处理音频采集:

void AudioThread::run(){
    QAudioInput input(device);
    QUdpSocket udpSocket;
    while(running){
        QByteArray audioData = input->readAll();
        udpSocket.writeDatagram(audioData, remoteAddr, 1234);
        QThread::usleep(50); // 控制发送频率
    }
}

接收端用QAudioOutput播放,注意这里要设置正确的音频格式参数。遇到卡顿的话可以加个环形缓冲区,攒够200ms的数据再播放。

文件传输得搞进度显示,咱们在协议头里加个文件MD5校验。大文件传输建议用内存映射:

QFile file(filePath);
if(!file.open(QIODevice::ReadOnly)) return;

uchar* mem = file.map(0, file.size());
if(mem){
    sendData((char*)mem, file.size());
    file.unmap(mem);
}

最后说几个实战遇到的坑:

  1. Qt的readyRead在高速传输时可能不触发,得手动调用readAll()
  2. 跨平台传输要注意字节序,用qToBigEndian转换
  3. UDP丢包严重的话可以加个简单的FEC前向纠错
  4. 线程退出时一定要先stop再delete,不然容易崩

代码量大概在3000行左右,核心是处理好协议封装和网络异常处理。想要完整源码的私,不过提醒下:这玩意儿需要自己配编译环境,搞不定的慎拍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值