C++ 简单的UDP客户端与服务端

.h

#pragma once
#ifndef __C_UDP_OBJECT_H__
#define __C_UDP_OBJECT_H__

#define OS_PLATFORM_WIN

#include <string>

#ifdef OS_PLATFORM_WIN

#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")

#else

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//#include <sys/un.h>  
//#include <netdb.h>

#endif // !OS_PLATFORM_WIN

class CUdpObject
{
protected:
    CUdpObject();
    virtual ~CUdpObject();

public:
    virtual void SetParameter(int nPort, const char* szAddress = nullptr);

public:
    virtual int SendTo(const char* szData, int nDataLength);
    virtual int ReceiveFrom(char* szBuffer, int nBufferSize);

public:
    virtual const std::string& ToString() = 0;

protected:
    virtual struct sockaddr_in& SocketAddress();

protected:
#ifdef OS_PLATFORM_WIN
    SOCKET m_sktUdpObject;
#else
    int m_sktUdpObject;
#endif // !OS_PLATFORM_WIN
    struct sockaddr_in m_sktUdpObjectAddress = { 0 };
    volatile int m_nLastSendTransferred = 0;
    volatile int m_nLastReceiveTransferred = 0;

private:
    int m_nPort = 0;
    char m_szAddress[32] = { 0 };

private:
    CUdpObject(const CUdpObject&);
    CUdpObject& operator=(const CUdpObject&);
};


class CUdpClient : public CUdpObject
{
public:
    CUdpClient() 
    { 
        m_strEndPoint = "C:" + std::to_string(m_sktUdpObject); 
        printf("ctor %s.\r\n", ToString().c_str());
    };
    virtual ~CUdpClient() 
    { 
        printf("dctor %s.\r\n", ToString().c_str()); 
    };

public:
    virtual bool IsConnect();

public:
    virtual const std::string& ToString() override;

private:
    std::string m_strEndPoint;

private:
    CUdpClient(const CUdpClient&);
    CUdpClient& operator=(const CUdpClient&);
};


//Single Client
class CUdpServer : public CUdpObject
{
public:
    CUdpServer() 
    { 
        m_strEndPoint = "S:" + std::to_string(m_sktUdpObject);
        printf("ctor %s.\r\n", ToString().c_str());
    };
    virtual ~CUdpServer() 
    { 
        printf("dctor %s.\r\n", ToString().c_str()); 
    };

public:
    void SetParameter(int nPort, const char* szAddress = nullptr) override;

public:
    struct sockaddr_in & SocketAddress() override;

public:
    virtual const std::string& ToString() override;

private:
    struct sockaddr_in m_sktAddressClient = { 0 };

private:
    std::string m_strEndPoint;

private:
    CUdpServer(const CUdpServer&);
    CUdpServer& operator=(const CUdpServer&);
};

#endif // !__C_UDP_OBJECT_H__

 

.cpp

#include "UdpObject.h"

#include <cstdio>
#include <cstdlib>
#include <cstring>


CUdpObject::CUdpObject()
{
#ifdef OS_PLATFORM_WIN
    WSADATA stData;
    WSAStartup(MAKEWORD(2, 2), &stData);
#else
#endif // !OS_PLATFORM_WIN

    m_sktUdpObject = socket(AF_INET, SOCK_DGRAM, 0/*IPPROTO_UDP, IPPROTO_UDPLITE*/);
}
CUdpObject::~CUdpObject()
{
#ifdef OS_PLATFORM_WIN
    closesocket(m_sktUdpObject);
    WSACleanup();
#else
    //shutdown(m_sktUdpObject, SHUT_RDWR);
    close(m_sktUdpObject);
#endif // !OS_PLATFORM_WIN
}

void CUdpObject::SetParameter(int nPort, const char* szAddress)
{
    m_nPort = nPort;

    m_sktUdpObjectAddress.sin_family = AF_INET;
    m_sktUdpObjectAddress.sin_port = htons(m_nPort);

    if (nullptr != szAddress)
    {
        std::strcpy(m_szAddress, szAddress);
        m_sktUdpObjectAddress.sin_addr.s_addr = inet_addr(m_szAddress);
    }
    else
    {
        m_sktUdpObjectAddress.sin_addr.s_addr = INADDR_ANY;
    }
}

struct sockaddr_in& CUdpObject::SocketAddress()
{
    return m_sktUdpObjectAddress;
}

int CUdpObject::SendTo(const char* szData, int nDataLength)
{
    struct sockaddr_in& sktAddress = SocketAddress();

#ifdef OS_PLATFORM_WIN
    int nSktAddressSize = sizeof(sktAddress);
#else
    socklen_t nSktAddressSize = sizeof(sktAddress);
#endif // !OS_PLATFORM_WIN

    m_nLastSendTransferred = sendto(m_sktUdpObject, szData, nDataLength, 0, (const struct sockaddr*)&sktAddress, sizeof(sktAddress));

    return m_nLastSendTransferred;
}

int CUdpObject::ReceiveFrom(char* szBuffer, int nBufferSize)
{
    struct sockaddr_in& sktAddress = SocketAddress();

#ifdef OS_PLATFORM_WIN
    int nSktAddressSize = sizeof(sktAddress);
#else
    socklen_t nSktAddressSize = sizeof(sktAddress);
#endif // !OS_PLATFORM_WIN

    m_nLastReceiveTransferred = recvfrom(m_sktUdpObject, szBuffer, nBufferSize, 0, (struct sockaddr*)&sktAddress, &nSktAddressSize);

    return m_nLastReceiveTransferred;
}



bool CUdpClient::IsConnect()
{
    return m_nLastSendTransferred >= 0 || m_nLastReceiveTransferred >= 0;
}

const std::string& CUdpClient::ToString()
{
    return m_strEndPoint;
}


void CUdpServer::SetParameter(int nPort, const char* szAddress)
{
    CUdpObject::SetParameter(nPort, nullptr);

    bind(m_sktUdpObject, (const struct sockaddr*)&m_sktUdpObjectAddress, sizeof(m_sktUdpObjectAddress));
}

struct sockaddr_in& CUdpServer::SocketAddress()
{
    return m_sktAddressClient;
}

const std::string& CUdpServer::ToString()
{
    return m_strEndPoint;
}

.test.cpp

 
#include <cstring>
#include <iostream>

#include "UdpObject.h"

using namespace std;
 


//int cudp_test()
int main()
{
    char szBuffer[128] = { 0 };

    CUdpServer server;
    server.SetParameter(60001);

    {
        CUdpClient client;
        client.SetParameter(60001, "192.168.1.76");


        std::strcpy(szBuffer, "abcedfe");
        std::cout << "Client Send: " << szBuffer << std::endl;
        client.SendTo(szBuffer, std::strlen(szBuffer));


        memset(szBuffer, 0, sizeof(szBuffer));
        server.ReceiveFrom(szBuffer, sizeof(szBuffer));
        std::cout << "Server Receive : " << szBuffer << std::endl;


        std::strcpy(szBuffer, "daaaaaaaaaaaaaaaaa");
        std::cout << "Server Send: " << szBuffer << std::endl;
        server.SendTo(szBuffer, std::strlen(szBuffer));


        memset(szBuffer, 0, sizeof(szBuffer));
        client.ReceiveFrom(szBuffer, sizeof(szBuffer));
        std::cout << "Client Receive : " << szBuffer << std::endl;

        std::cout << client.IsConnect() << std::endl;
    }

    {
        CUdpClient client;
        client.SetParameter(60001, "192.168.1.76");


        std::strcpy(szBuffer, "aassasaassasasasasaaas");
        std::cout << "Client Send: " << szBuffer << std::endl;
        client.SendTo(szBuffer, std::strlen(szBuffer));


        memset(szBuffer, 0, sizeof(szBuffer));
        server.ReceiveFrom(szBuffer, sizeof(szBuffer));
        std::cout << "Server Receive : " << szBuffer << std::endl;


        std::strcpy(szBuffer, "vdvdvdvdvdvdvdvdvdv");
        std::cout << "Server Send: " << szBuffer << std::endl;
        server.SendTo(szBuffer, std::strlen(szBuffer));


        memset(szBuffer, 0, sizeof(szBuffer));
        client.ReceiveFrom(szBuffer, sizeof(szBuffer));
        std::cout << "Client Receive : " << szBuffer << std::endl;

        std::cout << client.IsConnect() << std::endl;
    }
    
    std::cout << "Done." << std::endl;
    getchar();

    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.8.5)
project(upd_test)

set(TARGET ${PROJECT_NAME})


set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../../Release/)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
add_definitions(-DOS_PLATFORM_UNIX)

add_executable(${TARGET} UdpObject.cpp Test_UdpObject.cpp)
target_link_libraries(${TARGET})

 

.build.sh

#! /bin/sh

#
dirBuildShell="../Temp/"

#
if [ -d "${dirBuildShell}" ]; then
    rm -rf "${dirBuildShell}"
fi

#
if [ $# -ge 1 ]; then
    dirBuildShell="../$1/"
    rm -rf "${dirBuildShell}"
fi

#
if [ ! -d "${dirBuildShell}" ]; then
    mkdir "${dirBuildShell}"
    cd "${dirBuildShell}"
fi

#
cmake ../Test/ && make 

 

转载于:https://www.cnblogs.com/wjshan0808/p/9264731.html

C++中,实现一个UDP服务端,同时服务于多个客户端,需要处理好数据包的分发。由于UDP是无连接、不可靠的协议,服务端无法直接知道每个数据包来自哪个客户端。为了解决这个问题,通常可以采用以下策略: 1. **标识符**: 每个客户端连接时,可以在发送的数据包中附带一个唯一的标识符,如套接字地址或者自定义的ID。服务端通过接收数据包的源地址来关联响应。 ```cpp struct ClientData { std::string identifier; boost::asio::ip::udp::endpoint endpoint; // 或其他库提供的IP信息 }; std::map<std::string, ClientData> clients; ``` 2. **消息队列**: 使用队列存储未处理的消息,然后遍历队列查找对应的标识符来回应。 ```cpp class UDPServer { public: void handle_packet(const boost::system::error_code& error, size_t length, const boost::array<char, length>& data) { if (!error && length > 0) { std::string id = extractIdentifierFromPacket(data); // 提取标识符函数 auto it = clients.find(id); if (it != clients.end()) { sendReply(it->second.endpoint, data); } else { // 对于未知ID的客户端,可以选择忽略或记录日志 logUnknownClient(id); } } } private: void sendReply(const boost::asio::ip::udp::endpoint& client, const boost::array<char, length>& data) { // 发送回复到指定客户端 } }; ``` 3. **应答机制**: 当服务端收到一个请求时,除了处理该请求,还需要记住这个请求,并在后续接收到确认信息时,将应答发送给正确的客户端。 重要的是,由于UDP的不可靠性,这种设计依赖于客户端能够可靠地发送请求确认信息,否则服务端可能无法确定数据包的真实来源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值