c++ 网络编程udp协议 poco模块

官网资料(需要梯子):https://pocoproject.org/slides/200-Network.pdf
1、poco是在原生socket之上的封装,底层还是socket,性能低于socket,安全性和实用性高于socket,即使用简便,接口简单
2、udp协议是,接收端没有及时接收或者没有接收到这个数据,数据会丢失
3、很多案例,包括官网给出的案例,端口都是514,这个端口发送是没什么限制,但是接收会出现,I/O error,解决这个问题,要么换端口,要么执行加管理员权限。
原因:

在计算机网络中,端口514是专门保留给 syslog 服务的标准端口。虽然这个端口通常是为系统日志守护进程保留的,但它不是严格保留的,这意味着应用程序也可以使用它发送UDP数据包。然而,这个端口在许多系统中需要超级用户权限才能绑定并接收数据包。因此,发送UDP数据包到端口514通常不会有权限问题,但接收数据包时会因为缺少权限而失败。

下面是关于为什么你可以发送UDP数据包到端口514,而接收会遇到I/O错误的详细解释:

发送UDP数据包到端口514
发送数据包到一个端口并不需要对该端口的特殊权限。你只需要有权限打开一个任意的UDP套接字,并发送数据包到目的IP和端口。因此,在发送数据包到端口514时不会遇到权限问题。

接收UDP数据包在端口514
接收数据包需要将本地UDP套接字绑定到指定的端口。在Linux系统中,绑定到端口号小于1024的端口(也称为系统端口或保留端口)通常需要超级用户权限。端口514是一个保留端口,所以非超级用户尝试绑定到该端口时会失败,通常会抛出一个I/O错误

环境安装

sudo apt-get install libpoco-dev

使用示例,官网示例需要修改下端口:
udp发送

#include "Poco/Net/DatagramSocket.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Timestamp.h"
#include "Poco/DateTimeFormatter.h"
int main(int argc, char **argv)
{
    Poco::Net::SocketAddress sa("localhost", 1101);
    Poco::Net::DatagramSocket dgs;
    dgs.connect(sa);
    Poco::Timestamp now;
    std::string msg = Poco::DateTimeFormatter::format(now,
                                                      "<14>%w %f %H:%M:%S Hello, world!");
    dgs.sendBytes(msg.data(), msg.size());
    return 0;
}

udp接收

#include "Poco/Net/DatagramSocket.h"
#include "Poco/Net/SocketAddress.h"
#include <iostream>
int main(int argc, char **argv)
{
    // Poco::Net::SocketAddress sa(Poco::Net::IPAddress(), 514);
    Poco::Net::SocketAddress sa("localhost", 1101);
    Poco::Net::DatagramSocket dgs(sa);
    char buffer[1024];
    for (;;)
    {
        Poco::Net::SocketAddress sender;
        int n = dgs.receiveFrom(buffer, sizeof(buffer) - 1, sender);
        buffer[n] = '\0';
        std::cout << sender.toString() << ": " << buffer << std::endl;
    }
    return 0;
}

编译

g++ test1.cpp -lPocoNet -lPocoFoundation -o send
g++ test2.cpp -lPocoNet -lPocoFoundation -o receiv

组播发送示例一:

#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/MulticastSocket.h"
#include "Poco/DateTimeFormatter.h"
#include <iostream>
#include <cstring>
int main(int argc, char *argv[])
{
    try
    {
        Poco::Net::SocketAddress address("239.255.255.250", 1902);
        Poco::Net::MulticastSocket socket(
            Poco::Net::SocketAddress(
                Poco::Net::IPAddress(), address.port()));
        // to receive any data you must join
        socket.joinGroup(address.host());
        Poco::Net::SocketAddress sender;
        char buffer[512] = ""; // 字符串最好也要初始化,否则接收buffer,后会出现多余字符
        Poco::Timestamp now;
        std::string msg = Poco::DateTimeFormatter::format(now,
                                                          "%Y-%m-%d %H:%M:%S.%i send: Hello, world!");
        socket.sendTo(msg.data(), msg.size(), address); // 想要做监听程序:注释掉sendTo
        int n = socket.receiveFrom(buffer, sizeof(buffer), sender);
        std::cout << "Received message: " << buffer << " from " << sender.toString() << std::endl;
    }
    catch (Poco::Exception &e)
    {
        std::cerr << "Exception: " << e.displayText() << std::endl;
        return 1;
    }
    return 0;
}

组播模式注意事项:
1、“239.255.255.250”, 1902组合起来,类似于唯一标签,抓包可抓取"239.255.255.250"
2、1902为端口号,一定要检测一下,该端口号下,是否干扰包出现,出现即换端口
3、组播Poco::Net::SocketAddress address(“239.255.255.250”, 1902);需要在同网段唯一标签一致,才能通信
4、sender.toString()可查看来自哪个IP发送的信息

组播接收

#include <Poco/Net/DatagramSocket.h>
#include <Poco/Net/SocketAddress.h>
#include <Poco/Net/MulticastSocket.h>
#include <Poco/Net/NetworkInterface.h>
#include <iostream>
#include <vector>

int main() {
    try {
        // 设置组播地址和端口
        Poco::Net::SocketAddress multicastAddress("239.1.1.5", 9200);

        // 创建DatagramSocket
        Poco::Net::MulticastSocket socket(Poco::Net::IPAddress::IPv4);
        socket.bind(Poco::Net::SocketAddress(Poco::Net::IPAddress(), multicastAddress.port()), true);

        // 加入组播组
        Poco::Net::NetworkInterface iface = Poco::Net::NetworkInterface::forName("eth0.10"); // 使用实际的网络接口
        socket.joinGroup(multicastAddress.host(), iface);

        std::vector<char> buffer(1024);

        std::cout << "Listening for multicast messages on " << multicastAddress.toString() << " ..." << std::endl;

        while (true) {
            Poco::Net::SocketAddress sender;
            int n = socket.receiveFrom(&buffer[0], buffer.size(), sender);

            if (n > 0) {
                std::string message(buffer.begin(), buffer.begin() + n);
                std::cout << "Received message from " << sender.toString() << ": " << message << std::endl;
            }
        }

        // 离开组播组
        socket.leaveGroup(multicastAddress.host(), iface);
    } catch (Poco::Exception& ex) {
        std::cerr << "Poco Exception: " << ex.displayText() << std::endl;
    } catch (std::exception& ex) {
        std::cerr << "Standard Exception: " << ex.what() << std::endl;
    } catch (...) {
        std::cerr << "Unknown Exception!" << std::endl;
    }

    return 0;
}

附录: 时间模块

Poco::Timestamp now;
std::string msg = Poco::DateTimeFormatter::format(now, "%Y-%m-%d %H:%M:%S.%i ");
Poco::Int64 ms_msg = now.epochMicroseconds() / 1000;

// 数字转化为固定长度字符
Poco::Timestamp now;
// std::string msg = Poco::DateTimeFormatter::format(now, "%Y-%m-%d %H:%M:%S.%i ");
Poco::Int64 ms_msg= now.epochMicroseconds() / 1000;
std::string msg = std::to_string(ms_msg);
std::stringstream ss;
ss << std::setw(13) << std::setfill('0') << msg;  // 注意计算ms转化为字符串的长度
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值