/* * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved. * * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit). * * Use of this source code is governed by MIT license that can be found in the * LICENSE file in the root of the source tree. All contributing project authors * may be found in the AUTHORS file in the root of the source tree. */ #ifndef NETWORK_UDPCLIENT_H #define NETWORK_UDPCLIENT_H #include #include "Socket.h" #include "Util/SSLBox.h" #include "Kcp.h" namespace toolkit { //Udp客户端,Socket对象默认开始互斥锁 class UdpClient : public SocketHelper { public: using Ptr = std::shared_ptr; using OnRecvFrom = std::function; using OnErr = std::function; UdpClient(const EventPoller::Ptr &poller = nullptr); ~UdpClient() override; /** * 开始连接udp服务器 * @param peer_host 服务器ip或域名 * @param peer_port 服务器端口 * @param local_port 本地端口 */ virtual void startConnect(const std::string &peer_host, uint16_t peer_port, uint16_t local_port = 0); /** * 主动断开连接 * @param ex 触发onErr事件时的参数 */ void shutdown(const SockException &ex = SockException(Err_shutdown, "self shutdown")) override; /** * 连接中或已连接返回true,断开连接时返回false */ virtual bool alive() const; /** * 设置网卡适配器,使用该网卡与服务器通信 * @param local_ip 本地网卡ip */ virtual void setNetAdapter(const std::string &local_ip); /** * 唯一标识 */ std::string getIdentifier() const override; void setOnRecvFrom(OnRecvFrom cb) { _on_recvfrom = std::move(cb); } void setOnError(OnErr cb) { _on_err = std::move(cb); } protected: virtual void onRecvFrom(const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len) { if (_on_recvfrom) { _on_recvfrom(buf, addr, addr_len); } } void onRecv(const Buffer::Ptr &buf) override {} void onError(const SockException &err) override { DebugL; if (_on_err) { _on_err(err); } } /** * udp连接成功后每2秒触发一次该事件 */ void onManager() override {} private: mutable std::string _id; std::string _net_adapter = "::"; std::shared_ptr _timer; //对象个数统计 ObjectStatistic _statistic; OnRecvFrom _on_recvfrom; OnErr _on_err; }; //用于实现KCP客户端的模板对象 template class UdpClientWithKcp : public UdpClientType { public: using Ptr = std::shared_ptr; template UdpClientWithKcp(ArgsType &&...args) :UdpClientType(std::forward(args)...) { _kcp_box = std::make_shared(false); _kcp_box->setOnWrite([&](const Buffer::Ptr &buf) { public_send(buf); }); _kcp_box->setOnRead([&](const Buffer::Ptr &buf) { public_onRecv(buf); }); _kcp_box->setOnErr([&](const SockException &ex) { public_onErr(ex); }); } ~UdpClientWithKcp() override { } void onRecvFrom(const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len) override { //KCP 暂不支持一个UDP Socket 对多个目标,因此先忽略addr参数 _kcp_box->input(buf); } ssize_t send(Buffer::Ptr buf) override { return _kcp_box->send(std::move(buf)); } ssize_t sendto(Buffer::Ptr buf, struct sockaddr *addr = nullptr, socklen_t addr_len = 0) override { //KCP 暂不支持一个UDP Socket 对多个目标,因此先忽略addr参数 return _kcp_box->send(std::move(buf)); } inline void public_onRecv(const Buffer::Ptr &buf) { //KCP 暂不支持一个UDP Socket 对多个目标,因此固定采用bind的地址参数 UdpClientType::onRecvFrom(buf, (struct sockaddr*)&_peer_addr, _peer_addr_len); } inline void public_send(const Buffer::Ptr &buf) { UdpClientType::send(buf); } inline void public_onErr(const SockException &ex) { UdpClientWithKcp::onError(ex); } virtual void startConnect(const std::string &peer_host, uint16_t peer_port, uint16_t local_port = 0) override { _kcp_box->setPoller(UdpClientType::getPoller()); _peer_addr = SockUtil::make_sockaddr(peer_host.data(), peer_port); _peer_addr_len = SockUtil::get_sock_len((const struct sockaddr*)&_peer_addr); UdpClientType::startConnect(peer_host, peer_port, local_port); } void setMtu(int mtu) { _kcp_box->setMtu(mtu); } void setInterval(int intervoal) { _kcp_box->setInterval(intervoal); } void setRxMinrto(int rx_minrto) { _kcp_box->setRxMinrto(rx_minrto); } void setWndSize(int sndwnd, int rcvwnd) { _kcp_box->setWndSize(sndwnd, rcvwnd); } void setDelayMode(KcpTransport::DelayMode delay_mode) { _kcp_box->setDelayMode(delay_mode); } void setFastResend(int resend) { _kcp_box->setFastResend(resend); } void setFastackConserve(bool flag) { _kcp_box->setFastackConserve(flag); } void setNoCwnd(bool flag) { _kcp_box->setNoCwnd(flag); } void setStreamMode(bool flag) { _kcp_box->setStreamMode(flag); } private: struct sockaddr_storage _peer_addr; int _peer_addr_len = 0; KcpTransport::Ptr _kcp_box; }; } /* namespace toolkit */ #endif /* NETWORK_UDPCLIENT_H */