C++实现udp分包和组包

这篇具有很好参考价值的文章主要介绍了C++实现udp分包和组包。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

udp开发中的几个问题

1、udp数据是怎么发送的

UDP(user datagram protocol,用户数据报协议)是无连接的,面向消息的。不会使用块的合并优化算法,由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息)和结束标志, 即面向消息的通信是有消息保护边界的。
因此UDP是不会出现粘包的,但是会丢包。

2、tcp的处理方式

TCP是面向连接的,面向流的可靠性传输。TCP会将多个间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包发送,这样一个数据包里就可能含有多个消息的数据,面向流的通信是无消息保护边界的,也就是TCP粘包。接收端需要自己完成数据的拆包和组包,解决粘包问题。

3、udp的MTU值

MTU = 1500 - IP头(20) - UDP头(8) = 1472(Bytes)(局域网)
MTU = 576 - 20 - 8 = 548(Internet互联网标准)
如果发送数据包大于MTU,则会出现严重丢包,甚至sendto返回失败。

4、udp大于MTU值怎么处理

1、UDP发送的数据报大小 <= MTU时,发送端直接发送,接收端无需组包。
2、UDP发送的数据报大小 > MTU时,发送端必须进行拆包发送,接收端收到包以后组包。

udp分包和组包策略

1、给每个整包分配一个唯一的序列号sequence,组包时根据序列号判断分包属于哪个整包。
2、每个子包分配一个index序号,用于接收端按顺序组包。
3、udp包是独立的,因此分包后,每个包都要有可识别的公共包头。
4、等所有分包都接收完成再进行组包。
5、udp是不可靠传输,如果分包的其中一个子包丢了,那么整个包将被丢弃(重传依赖其他响应机制)。
6、udp是无序的,发送端按序发,接收端收到包可能是乱序的,组包时要按顺序组包。
7、udp支持一对多通信,如果同时接收多个客户端的消息,多个客户端的消息会交叉到达,需要单独处理每个客户端的消息。

6 和 7 是实现的难点。

C++实现udp分包

写个udp客户端,往指定udp服务端发送数据,for循环连续发送多个包,发送间隔依据机器性能,性能好的机器可以无间隔发送(nosleep)还能保证不丢包。
可启动多个客户端同时向服务端发送数据,测试组包。

客户端实现:

#ifndef UDPCLIENT_H
#define UDPCLIENT_H

#include "SocketInclude.h"
class UdpClient
{
public:
    UdpClient();
    ~UdpClient();
    int CreateUdpCli(uint32_t serverIp, uint16_t _uListenPort);
    int dealUdpSendData();
private:
    UdpClientDef*    pUdpClientDef;
};
#endif //UDPCLIENT_H
#include "UdpClient.h"
#include <string>

UdpClient::UdpClient()
{
    pUdpClientDef = new UdpClientDef;
}

UdpClient::~UdpClient()
{
    delete pUdpClientDef;
}

//本端是客户端,udp客户端建链
int UdpClient::CreateUdpCli(uint32_t serverIp,uint16_t _uListenPort)
{
    return CreateUdpClient(pUdpClientDef,serverIp,_uListenPort);
}

//处理udp数据发送
int UdpClient::dealUdpSendData()
{
    static unsigned int sequence_whole = 0;//整包的序号
    //原始数据包
    uint32_t dataLength = 5000;
    void *sendbuff = new char[dataLength];
    CommMsgHdr* pHead = (CommMsgHdr*)sendbuff;

    pHead->uMsgType = 631;
    pHead->uTotalLen = dataLength;

    //开始分包
    int packetNum = dataLength / UDP_PAYLOAD;//分包数量
    int lastPaketSize = dataLength % UDP_PAYLOAD;//最后一片包的大小
    int sequence = 0;//当前发送的包序号
    if (lastPaketSize != 0)
    {
        packetNum = packetNum + 1;
    }

    //分包的包头
    MergeHdr tMergeHdr;
    tMergeHdr.uAllPktSize = dataLength;//负载总大小
    tMergeHdr.uPieces = packetNum;//分包数量
    tMergeHdr.uSequence = sequence_whole++;
    tMergeHdr.msgHead.uMsgType = 635;

    unsigned char piecebuff[UDP_PAYLOAD + sizeof(MergeHdr)];
    while (sequence < packetNum)
    {
        memset(piecebuff,0,UDP_PAYLOAD + sizeof(MergeHdr));
        if (sequence < (packetNum-1))//不是最后一片
        {
            tMergeHdr.uCurPktSize = sizeof(MergeHdr) + UDP_PAYLOAD;//当前包大小
            tMergeHdr.uIndex = sequence + 1;//当前包序号
            tMergeHdr.uOffset = sequence * UDP_PAYLOAD;//当前包偏移
            tMergeHdr.msgHead.uTotalLen  = tMergeHdr.uCurPktSize;
            memcpy(piecebuff, &tMergeHdr, sizeof(MergeHdr));
            memcpy(piecebuff+sizeof(MergeHdr), (char*)sendbuff+tMergeHdr.uOffset, UDP_PAYLOAD);

            ssize_t send_len = ::sendto(pUdpClientDef->fd, (const char*)piecebuff, tMergeHdr.uCurPktSize, 0, (struct sockaddr*) &pUdpClientDef->remote_addr,sizeof(struct sockaddr));
            if(send_len!=tMergeHdr.uCurPktSize)
            {
                printf("udp send failed,errno=[%d]\n",errno);
            }

            sequence ++;
        }
        else//最后一片
        {
            tMergeHdr.uCurPktSize = sizeof(MergeHdr)+(dataLength - sequence * UDP_PAYLOAD);
            tMergeHdr.uIndex = sequence + 1;
            tMergeHdr.uOffset = sequence * UDP_PAYLOAD;
            tMergeHdr.msgHead.uTotalLen  = tMergeHdr.uCurPktSize;
            memcpy(piecebuff, &tMergeHdr, sizeof(MergeHdr));
            memcpy(piecebuff+sizeof(MergeHdr), (char*)sendbuff+tMergeHdr.uOffset, dataLength - sequence*UDP_PAYLOAD);
            ssize_t send_len = ::sendto(pUdpClientDef->fd, (const char*)piecebuff, tMergeHdr.uCurPktSize, 0, (struct sockaddr*) &pUdpClientDef->remote_addr,sizeof(struct sockaddr));
            if(send_len!=tMergeHdr.uCurPktSize)
            {
                printf("udp send failed,errno=[%d]\n",errno);
            }

            sequence ++;
        }
    }
    delete[] (char *)(sendbuff), sendbuff = NULL;
    return 0;
}

结构体定义:

#ifndef SOCKETINCLUE_H
#define SOCKETINCLUE_H

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h> // for open
#include <unistd.h> // for close
#include <map>
#include <netinet/tcp.h>
#include <string.h>
#include <vector>

#define UDP_MTU             1472
#define MAX_EPOLL_EVENTS    1024         //epoll监听最大事件数量,对应最大连接socket数量

#pragma pack(push, 1)

//业务包头
struct CommMsgHdr
{
    uint16_t uMsgType;
    uint32_t uTotalLen;
};

//分包包头
struct MergeHdr
{
    CommMsgHdr  msgHead;//公共包头
    unsigned int uSequence;//整包的序号
    unsigned int uCurPktSize;//当前包的大小(sizeof(MergeHdr)+负载长度)
    unsigned int uAllPktSize;//数据的总大小
    unsigned int uPieces;//数据被分成包的个数
    unsigned int uIndex;//数据包当前的帧号
    unsigned int uOffset;//数据包在整个数据中的偏移
};
#define UDP_PAYLOAD         ( UDP_MTU - sizeof(MergeHdr) )    //互联网udp有效负载

//单个Sequence的所有包
struct pkt_merge
{
    void* mergebuff        = nullptr ;  //合并后的数据
    int  uAllPktSize       = 0;     //接收总长度
    unsigned int uSequence = 0;     //整包的序号
    unsigned int uPieces;           //数据被分成包的个数

    std::map<unsigned int,void*> mRcvData;//暂存接收的包<index,data>
};

//udp客户端
typedef struct _UdpClientDef_{
    int32_t             fd;              //fd,如果是服务端则统一使用服务端的fd,根据地址区分不同客户端
    struct sockaddr_in  remote_addr;     //对端地址
    std::map<int,pkt_merge*> m_pkt_merge;//<sequence,pkt_merge>,需要组包时,暂存包
}UdpClientDef;

//udp服务端
typedef struct _UdpServerDef_{
    int32_t fd;                         //fd
    struct sockaddr_in local_addr;      //本端地址
}UdpServerDef;

#pragma pack(pop)

int32_t CreateUdpClient(UdpClientDef* udp, uint32_t remoteIp, int32_t remotePort);
int32_t CreateUdpServer(UdpServerDef *udp, int32_t plocalPort);

#endif // SOCKETINCLUE_H

#include "SocketInclude.h"

//创建udp套接字
int32_t CreateUdpClient(UdpClientDef* udp, uint32_t remoteIp, int32_t remotePort)
{
    if (udp == NULL)		return -1;
    udp->fd = -1;

    udp->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    fcntl(udp->fd, F_SETFL, O_NONBLOCK);//设置非阻塞
    if(udp->fd < 0)
    {
        printf("[CreateUdpClient] create udp socket failed,errno=[%d],remoteIp=[%u],remotePort=[%d]",errno,remoteIp,remotePort);
        return -1;
    }

    udp->remote_addr.sin_family = AF_INET;
    udp->remote_addr.sin_port = htons(remotePort);
    udp->remote_addr.sin_addr.s_addr = remoteIp;
    return 0;
}

int32_t CreateUdpServer(UdpServerDef *udp, int32_t plocalPort)
{
    if (udp == NULL)		return -1;
    udp->fd = -1;

    udp->local_addr.sin_family = AF_INET;
    udp->local_addr.sin_port = htons(plocalPort);
    udp->local_addr.sin_addr.s_addr = INADDR_ANY;

    udp->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if(udp->fd < 0)
    {
        printf("[CreateUdpServer] create udp socket failed,errno=[%d],plocalPort=[%d]",errno,plocalPort);
        return -1;
    }

    //2.socket参数设置
    int opt = 1;
    setsockopt(udp->fd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//chw
    fcntl(udp->fd, F_SETFL, O_NONBLOCK);//设置非阻塞

    if (bind(udp->fd, (struct sockaddr*) &udp->local_addr,sizeof(struct sockaddr_in)) < 0)
    {
        close(udp->fd);
        printf("[CreateUdpServer] Udp server bind failed,errno=[%d],plocalPort=[%d]",errno,plocalPort);
        return -2;
    }

    return 0;
}

调用方式:

UdpClient mUdpClient;
uint32_t serverIp = inet_addr("127.0.0.1");
mUdpClient.CreateUdpCli(serverIp,9090);

for(int index=0;index<ui->lineEdit->text().toInt();index++)
{
        mUdpClient.dealUdpSendData();
        usleep(1000 * 10);
}

C++实现udp组包

写个udp服务端,绑定端口,使用epoll监听接收。文章来源地址https://www.toymoban.com/news/detail-597503.html

#ifndef UDPSERVER_H
#define UDPSERVER_H

#include "SocketInclude.h"
using namespace std;
class UdpServer
{
public:
    UdpServer();
    ~UdpServer();
    bool StartUp(uint16_t _uListenPort);//启动服务
private:
    static void* ThreadCallBack(void *arg);//创建线程函数
    void DealUdpThread();//udp线程处理函数
    void TryMergePkt(int index, unsigned int seq);//尝试组包
    void DelMergePkt(int index, unsigned int seq);//释放包
    void SetUdpEpollFlag(int fd, bool flag);

private:
    UdpServerDef*    pUdpServerDef;    //udp服务端对象
    pthread_t        m_threadId;    //udp线程ID
    int              m_epoll_fd;    //epollfd
    bool             m_bIsRunning;  //线程是否运行
    vector<UdpClientDef> m_vUdpClientDef;
};
#endif //UDPSERVER_H

#include "UdpServer.h"
#include <string>
#include <sys/epoll.h>
#include <QDebug>

UdpServer::UdpServer()
{
    pUdpServerDef = new UdpServerDef;
    m_epoll_fd = epoll_create(1);
    m_bIsRunning = true;
}

UdpServer::~UdpServer()
{
    m_bIsRunning = false;
}

bool UdpServer::StartUp(uint16_t _uListenPort)
{
    if(CreateUdpServer(pUdpServerDef,_uListenPort) == 0)
    {
        SetUdpEpollFlag(pUdpServerDef->fd,true);
    }

    if(pthread_create(&m_threadId, nullptr, ThreadCallBack, this))
    {
        printf("[UdpServer::StartUp] create thread failed.");
        return false;
    }

    return true;
}

//TCP服务监听线程,处理接入监听,客户端断开/错误管理
void* UdpServer::ThreadCallBack(void *arg)
{
    UdpServer *tm = static_cast<UdpServer *>(arg);
    if(tm)
        tm->DealUdpThread();
    return nullptr;
}

void UdpServer::DealUdpThread()
{
    const int kEpollDefaultWait = 1;//超时时长,单位ms
    struct epoll_event alive_events[MAX_EPOLL_EVENTS];

    void* bigBuffer = NULL;
    int  mergeRcvLen = 0;
    static unsigned int sequence = 1;
    while (m_bIsRunning)
    {
        int num = epoll_wait(m_epoll_fd, alive_events, MAX_EPOLL_EVENTS, kEpollDefaultWait);
        for (int i = 0; i < num; ++i)
        {
            int fd = alive_events[i].data.fd;
            int events = alive_events[i].events;

            if ( events & EPOLLIN )
            {
                char recv_buffer[UDP_MTU];
                memset(recv_buffer,0,UDP_MTU);
                ssize_t recv_len = 0;
                socklen_t src_len = sizeof(struct sockaddr_in);
                struct sockaddr_in SrcAddr;
                memset(&SrcAddr, 0, src_len);

                //1.开始接收
                struct sockaddr_in remote_addr;
                if ((recv_len = recvfrom(fd, recv_buffer, UDP_MTU, 0,	(struct sockaddr*) &SrcAddr, &src_len)) > 0)
                {
                    remote_addr.sin_port = SrcAddr.sin_port;
                    remote_addr.sin_addr.s_addr = SrcAddr.sin_addr.s_addr;

                    //判断是否已记录该客户端
                    bool isExist = false;
                    for(int index=0;index<m_vUdpClientDef.size();index++)
                    {
                        if(m_vUdpClientDef[index].remote_addr.sin_addr.s_addr == remote_addr.sin_addr.s_addr
                        && m_vUdpClientDef[index].remote_addr.sin_port        == remote_addr.sin_port)
                        {
                            isExist = true;
                            break;
                        }
                    }
                    if(!isExist)
                    {
                        UdpClientDef tUdpClientDef;
                        tUdpClientDef.fd = fd;
                        tUdpClientDef.remote_addr = remote_addr;
                        m_vUdpClientDef.push_back(tUdpClientDef);
                    }
                }
                else
                    continue;

                //1.不需要组包
                if( ((CommMsgHdr *)recv_buffer)->uMsgType != 635)
                {
                    //直接分发处理
                }

                //2.需要组包,处理错序
                for(int index=0;index<m_vUdpClientDef.size();index++)
                {
                    if(m_vUdpClientDef[index].remote_addr.sin_addr.s_addr == remote_addr.sin_addr.s_addr
                    && m_vUdpClientDef[index].remote_addr.sin_port        == remote_addr.sin_port)
                    {
                        MergeHdr* tMergeHdr = (MergeHdr*)recv_buffer;

                        if(m_vUdpClientDef[index].m_pkt_merge.count(tMergeHdr->uSequence) > 0)
                        {
                            //已存在该Sequence的包
                            m_vUdpClientDef[index].m_pkt_merge[tMergeHdr->uSequence]->uAllPktSize += tMergeHdr->uCurPktSize - sizeof(MergeHdr);;
                        }
                        else
                        {
                            //新Sequence的包
                            //建议新增定时器,在一定时间内没有收完包,则丢弃包
                            pkt_merge *tpkt_merge = new pkt_merge;
                            tpkt_merge->uSequence = tMergeHdr->uSequence;
                            tpkt_merge->uAllPktSize = tMergeHdr->uCurPktSize - sizeof(MergeHdr);
                            tpkt_merge->uPieces = tMergeHdr->uPieces;
                            tpkt_merge->mergebuff = new char[tMergeHdr->uAllPktSize];

                            m_vUdpClientDef[index].m_pkt_merge[tMergeHdr->uSequence] = tpkt_merge;
                        }
                        //todo,如果已存在key,存在泄漏
                        void* buff = new char[UDP_MTU];
                        memcpy(buff,recv_buffer,UDP_MTU);
                        m_vUdpClientDef[index].m_pkt_merge[tMergeHdr->uSequence]->mRcvData[tMergeHdr->uIndex] = buff;

                        TryMergePkt(index,tMergeHdr->uSequence);
                    }
                }

#if 0         //3.需要组包,不处理错序,此时如果同时接收两个客户端的数据,则可能出现错序
              if( ((CommMsgHdr *)recv_buffer)->uMsgType == 635)
                {
                    MergeHdr* tMergeHdr = (MergeHdr*)recv_buffer;
                    //根据sequence按顺序接收
                    if(sequence == tMergeHdr->uIndex)
                    {
                        sequence++;
                        if(bigBuffer == nullptr)
                            bigBuffer = new char[tMergeHdr->uAllPktSize];
                        mergeRcvLen += tMergeHdr->uCurPktSize - sizeof(MergeHdr);

                        memcpy((char*)bigBuffer+tMergeHdr->uOffset, recv_buffer + sizeof(MergeHdr),
                               tMergeHdr->uCurPktSize - sizeof(MergeHdr));
                        if ((tMergeHdr->uPieces == tMergeHdr->uIndex)
                                && (mergeRcvLen == tMergeHdr->uAllPktSize))
                        {
                            //组包完成
                            CommMsgHdr* pMsg = (CommMsgHdr*)bigBuffer;
                            printf("pMsg.uMsgType=%d\n",pMsg->uMsgType);
                            printf("pMsg.uTotalLen=%d\n",pMsg->uTotalLen);
                            printf("remote_addr.sin_port=%d\n",ntohs(remote_addr.sin_port));

                            mergeRcvLen = 0;
                            delete[] (char *)(bigBuffer);
                            bigBuffer = NULL;
                            sequence = 1;
                        }
                    }
                    //如果出现错序或乱序,丢弃包
                    else
                    {
                        mergeRcvLen = 0;
                        delete[] (char *)(bigBuffer);
                        bigBuffer = NULL;
                        sequence = 1;
                        printf(" miss-sequence \n");
                    }
                }
#endif
            }
        }

    }
}

//尝试组包
void UdpServer::TryMergePkt(int index, unsigned int seq)
{
    pkt_merge *tpkt_merge = m_vUdpClientDef[index].m_pkt_merge[seq];
    if(tpkt_merge->uPieces > tpkt_merge->mRcvData.size())
    {
        //还没收完所有的包,不组包
        auto last_ite = tpkt_merge->mRcvData.end();
        last_ite --;
        //如果此时收到的 分包序列号 >= 包的总数,则说明中间有丢包,此时丢弃包
        if(last_ite->first >= tpkt_merge->uPieces)
        {
            DelMergePkt(index, seq);
            printf("error,miss sequence\n");
        }
    }
    else if(tpkt_merge->uPieces < tpkt_merge->mRcvData.size())
    {
        //收到包的数量大于分片数量,出现异常,丢弃包
        printf("error,recv too many bags\n");
        DelMergePkt(index, seq);
    }
    else
    {
        //已经收完所有分包,开始组包
        auto ite = tpkt_merge->mRcvData.begin();
        while(ite != tpkt_merge->mRcvData.end())
        {
            MergeHdr* tMergeHdr = (MergeHdr*)ite->second;
            memcpy((char*)tpkt_merge->mergebuff+tMergeHdr->uOffset, (char*)ite->second + sizeof(MergeHdr),
                   tMergeHdr->uCurPktSize - sizeof(MergeHdr));
            ++ ite;
        }

        ite --;
        MergeHdr* tMergeHdr = (MergeHdr*)ite->second;
        if ((tpkt_merge->uPieces == tMergeHdr->uIndex)
                && (tpkt_merge->uAllPktSize == tMergeHdr->uAllPktSize))
        {
            //组包完成,分发处理
            CommMsgHdr* pMsg = (CommMsgHdr*)tpkt_merge->mergebuff;
            printf("pMsg.uMsgType=%d\n",pMsg->uMsgType);
            printf("pMsg.uTotalLen=%d\n",pMsg->uTotalLen);

            //释放资源
            DelMergePkt(index, seq);
        }
    }
}

void UdpServer::DelMergePkt(int index, unsigned int seq)
{
    pkt_merge *tpkt_merge = m_vUdpClientDef[index].m_pkt_merge[seq];

    auto ite_2 = tpkt_merge->mRcvData.begin();
    while(ite_2 != tpkt_merge->mRcvData.end())
    {
        delete[] (char *)(ite_2->second);
        ite_2++;
    }
    delete[] (char *)(tpkt_merge->mergebuff);
    tpkt_merge->mRcvData.clear();
    m_vUdpClientDef[index].m_pkt_merge.erase(m_vUdpClientDef[index].m_pkt_merge.find(tpkt_merge->uSequence));
}

//设置epoll监听udp套接字,只监听EPOLLIN事件
void UdpServer::SetUdpEpollFlag(int fd, bool flag)
{
    struct epoll_event evt;
    evt.events = EPOLLIN;
    evt.data.fd = fd;
    if(flag)
        epoll_ctl(m_epoll_fd,EPOLL_CTL_ADD,fd,&evt);
    else
        epoll_ctl(m_epoll_fd,EPOLL_CTL_DEL,fd,&evt);
}

到了这里,关于C++实现udp分包和组包的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】6.网络编程:网络编程(TCP&UDP)

    网络编程是C++ API操作中很重要的一部分,包含 TCP 和 UDP 。 网络传输模型可以抽象为7个层: 物理层、数据链路层、网络层、传输层、会话层、表示层、应用层 。 但在使用TCP/IP协议时,可以简化为这4层: 网络接口、网络层、传输层、应用层 。 TCP:可靠传输,三次握手建立

    2024年02月16日
    浏览(43)
  • C++实现简单UDP通信

    发送端向接收端发送数据,ip地址和端口号要与 接收端 一致     cpp_UDP客户端,发送端

    2024年02月11日
    浏览(36)
  • C++开发基础之网络编程WinSock库使用详解TCP/UDP Socket开发

    Winsock是Windows操作系统提供的用于网络编程的API库。它是Windows Sockets的简称,也就是套接字库。Winsock可以让开发人员使用TCP/IP协议族中的各种协议,如TCP、UDP等,在Windows平台下进行网络编程。 Winsock提供了一组函数和数据结构,这些函数和数据结构可以让开发人员创建和管理

    2024年01月23日
    浏览(51)
  • c++ 之 socket udp与tcp client server实现

    socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用打开open – 读写write/read – 关闭close模式来操作。Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭). 说白了Socket是应用层与TCP/IP协议族通

    2023年04月15日
    浏览(45)
  • 14-3_Qt 5.9 C++开发指南_QUdpSocket实现 UDP 通信_UDP 单播和广播

    UDP(User Datagram Protocol,用户数据报协议)是轻量的、不可靠的、面向 数据报 (datagram) 、无连接的协议,它可以用于对可靠性要求不高的场合。与 TCP 通信不同, 两个程序之间进行 UDP 通信无需预先建立持久的 socket 连接,UDP 每次发送数据报都需要指定目标地址和端口 (如图14-6

    2024年02月14日
    浏览(51)
  • c++神经网络算法实现

    #include iostream #include vector #include cmath #include cstdlib #include ctime #include algorithm #include Eigen/Dense using namespace std; using namespace Eigen; // 定义常量 const int INPUT_NUM = 784; // 输入层节点数 const int HIDDEN_NUM = 100; // 隐藏层节点数 const int OUTPUT_NUM = 10; // 输出层节点数 const double LEARNING_RATE = 0.

    2024年02月07日
    浏览(29)
  • C++中UDP通讯详解

    /************************************** 1、一个socket实现udp收发 socket用于udp通信时,是不区分Server与Client的。因为是无连接的,发送完了也就完了。同样接收到数据也就完成了一次通信。因此,Server端与Client端的措辞在Udp通信中的含义其实就退化了。 将socket用于tcp编程时,都比较喜欢

    2024年02月01日
    浏览(27)
  • C++实现socket网络通信

    🍺SOCKET网络通信系列文章链接如下:🍺 🎈【小沐学python】(一)Python简介和安装🎈 🎈Python实现socket网络通信🎈 🎈C++实现socket网络通信🎈 🎈Android实现socket网络通信🎈 🎈nodejs实现socket网络通信🎈 《斗诗篇》 陈献章: 窗外竹青青,窗间人独坐。 究竟竹与人,原来无两

    2023年04月09日
    浏览(39)
  • C++ 简单实现RPC网络通讯

            RPC是远程调用系统简称,它允许程序调用运行在另一台计算机上的过程,就像调用本地的过程一样。RPC 实现了网络编程的“过程调用”模型,让程序员可以像调用本地函数一样调用远程函数。最近在做的也是远程调用过程,所以通过重新梳理RPC来整理总结一下。  

    2023年04月08日
    浏览(44)
  • C++ UDP连接方式(QT版)

    UdpSocket.h UdpSocket.cpp

    2024年02月15日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包