当前位置: 首页 > news >正文

16.udp_socket(三)

一.概念回顾

建议先学上篇博客,再向下学习,上篇博客的链接如下:

https://blog.csdn.net/weixin_60668256/article/details/154725707?fromshare=blogdetail&sharetype=blogdetail&sharerId=154725707&sharerefer=PC&sharesource=weixin_60668256&sharefrom=from_link

二.重定向补充知识

#include <cstdio>
#include <iostream>int main()
{//标志输出std::cout << "hello cout" << std::endl;printf("hello printf\n");//标志错误std::cerr << "hello cerr" << std::endl;fprintf(stderr,"hello fprintf\n");return 0;
}

#include "UdpClient.hpp"
#include <iostream>
#include <cstring>
#include <string.h>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Common.hpp"
#include <pthread.h>int sockfd = -1;void* Recver(void* args)
{while(true){struct sockaddr_in temp;socklen_t len = sizeof(temp);char buffer[1024];int n = ::recvfrom(sockfd,buffer,sizeof(buffer)-1,0,CONV(&temp),&len);if(n > 0){buffer[n] = 0;std::cerr << buffer << std::endl;}}return nullptr;
}// ./client_udp serverip serverport
int main(int argc,char* argv[])
{if(argc != 3){std::cerr << "Usage: " << argv[0] << " serverip serverport" << std::endl;Die(USAGE_ERR);}std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);//1.创建socketsockfd = ::socket(AF_INET,SOCK_DGRAM,0);if (sockfd < 0){std::cerr << "scoket error" << std::endl;Die(SOCKET_ERR);}//1.1填充server信息struct sockaddr_in server;memset(&server,0,sizeof(server));server.sin_family = AF_INET;server.sin_port = ::htons(serverport); //要被发送给对方的,即要发送到网络中server.sin_addr.s_addr = ::inet_addr(serverip.c_str());pthread_t tid;pthread_create(&tid,nullptr,Recver,nullptr);//2.client donewhile(true){std::cout << "please Enter# " << std::endl;std::string message;std::getline(std::cin,message);// client 不需要进行bind吗? socket <->socket// client 必须要有自己的ip和端口!但是客户端,不需要自己显示调用bind!!// 而是,客户端首次sendto消息的时候,由OS自动进行bind// 1.如何理解client自动随机bind端口号?    一个端口号,由OS自动进行bind(客户端不需要被人找到)// 2.如何理解server需要显示的bind?        服务器端口号必须稳定,所以这里不能由OS随机bindint n = ::sendto(sockfd,message.c_str(),message.size(),0,CONV(&server),sizeof(server));(void)n;}return 0;
}

服务器转发的是2号信号,所以会在上面汇总

这样就能很好的进行区分了

三.代码细节补充

1.对用户管理模块进行加锁

class UserManager
{
public:UserManager(){}void AddUser(InetAddr& id){LockGuard lockguard(_mutex);for(auto& user : _online_user){if(*user == id){return;}}LOG(LogLevel::INFO) << "新增该用户: " << id.Addr();_online_user.push_back(std::make_shared<User>(id));}void DelUser(const InetAddr& user){}void Router(int sockfd,const std::string& message){LockGuard lockguard(_mutex);for(auto& user:_online_user){user->SendTo(sockfd,message);}}~UserManager(){}
private:std::list<std::shared_ptr<UserInterface>> _online_user;Mutex _mutex;
};

2.消息发送的用户显示

void Start(){_isrunning = true;while(true){char inbuffer[1024];struct sockaddr_in peer;socklen_t len = sizeof(peer);ssize_t n = ::recvfrom(_sockfd,inbuffer,sizeof(inbuffer)-1,0,CONV(&peer),&len);if(n > 0){//1.消息内容 && 2.谁给我发的InetAddr cli(peer);inbuffer[n] = 0;std::string message = cli.Addr() + "# " + inbuffer;//2.新增用户_adduser(cli);//3.新增转发模块task_t task = std::bind(UdpServer::_route,_sockfd,message);ThreadPool<task_t>::getInstance()->Equeue(task);std::string clientinfo = cli.Ip() + " : " + std::to_string(cli.Port()) + " # " + inbuffer;LOG(LogLevel::DEBUG) << clientinfo;std::string echo_string = "echo# ";echo_string += inbuffer;::sendto(_sockfd,echo_string.c_str(),echo_string.size(),0,CONV(&peer),sizeof(peer));}}_isrunning = false;}

这样我们再启动的时候,绑定的端口就能识别到

3.加入用户提醒

#include "UdpClient.hpp"
#include <iostream>
#include <cstring>
#include <string.h>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Common.hpp"
#include <pthread.h>int sockfd = -1;void* Recver(void* args)
{while(true){struct sockaddr_in temp;socklen_t len = sizeof(temp);char buffer[1024];int n = ::recvfrom(sockfd,buffer,sizeof(buffer)-1,0,CONV(&temp),&len);if(n > 0){buffer[n] = 0;std::cerr << buffer << std::endl;}}return nullptr;
}// ./client_udp serverip serverport
int main(int argc,char* argv[])
{if(argc != 3){std::cerr << "Usage: " << argv[0] << " serverip serverport" << std::endl;Die(USAGE_ERR);}std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);//1.创建socketsockfd = ::socket(AF_INET,SOCK_DGRAM,0);if (sockfd < 0){std::cerr << "scoket error" << std::endl;Die(SOCKET_ERR);}//1.1填充server信息struct sockaddr_in server;memset(&server,0,sizeof(server));server.sin_family = AF_INET;server.sin_port = ::htons(serverport); //要被发送给对方的,即要发送到网络中server.sin_addr.s_addr = ::inet_addr(serverip.c_str());pthread_t tid;pthread_create(&tid,nullptr,Recver,nullptr);//1.2启动的时候,给服务器推送消息即可const std::string online = "...来了哈!";int n = ::sendto(sockfd,online.c_str(),online.size(),0,CONV(&server),sizeof(server));//2.client donewhile(true){std::cout << "please Enter# " << std::endl;std::string message;std::getline(std::cin,message);int n = ::sendto(sockfd,message.c_str(),message.size(),0,CONV(&server),sizeof(server));(void)n;}return 0;
}

4.退出消息提醒 及 功能实现

#include "UdpClient.hpp"
#include <iostream>
#include <cstring>
#include <string.h>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Common.hpp"
#include <pthread.h>
#include <signal.h>int sockfd = -1;
struct sockaddr_in server;void ClientQuit(int signo)
{(void)signo;const std::string quit = "Quit!";int n = ::sendto(sockfd,quit.c_str(),quit.size(),0,CONV(&server),sizeof(server));
}void* Recver(void* args)
{while(true){struct sockaddr_in temp;socklen_t len = sizeof(temp);char buffer[1024];int n = ::recvfrom(sockfd,buffer,sizeof(buffer)-1,0,CONV(&temp),&len);if(n > 0){buffer[n] = 0;std::cerr << buffer << std::endl;}}return nullptr;
}// ./client_udp serverip serverport
int main(int argc,char* argv[])
{if(argc != 3){std::cerr << "Usage: " << argv[0] << " serverip serverport" << std::endl;Die(USAGE_ERR);}signal(2,ClientQuit);std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);//1.创建socketsockfd = ::socket(AF_INET,SOCK_DGRAM,0);if (sockfd < 0){std::cerr << "scoket error" << std::endl;Die(SOCKET_ERR);}//1.1填充server信息memset(&server,0,sizeof(server));server.sin_family = AF_INET;server.sin_port = ::htons(serverport); //要被发送给对方的,即要发送到网络中server.sin_addr.s_addr = ::inet_addr(serverip.c_str());pthread_t tid;pthread_create(&tid,nullptr,Recver,nullptr);//1.2启动的时候,给服务器推送消息即可const std::string online = "...来了哈!";int n = ::sendto(sockfd,online.c_str(),online.size(),0,CONV(&server),sizeof(server));//2.client donewhile(true){std::cout << "please Enter# " << std::endl;std::string message;std::getline(std::cin,message);int n = ::sendto(sockfd,message.c_str(),message.size(),0,CONV(&server),sizeof(server));(void)n;}return 0;
}

void RegisterService(adduser_t adduser,route_t route,remove_t remove){_adduser = adduser;_route = route;_remove = remove;}
#include "UdpServer.hpp"
#include "User.hpp"// ./server_udp localport
int main(int argc,char* argv[])
{if(argc != 2){std::cerr << "Usage: " << argv[0] << " localport" << std::endl;Die(USAGE_ERR);}uint16_t port = std::stoi(argv[1]);ENABLE_CONSOLE_LOG();std::shared_ptr<UserManager> um = std::make_shared<UserManager>();std::unique_ptr<UdpServer> svr_uptr = std::make_unique<UdpServer>(port);svr_uptr->RegisterService([&um](InetAddr& id){um->AddUser(id);},[&um](int sockfd,const std::string& message){um->Router(sockfd,message);},[&um](InetAddr& id){um->DelUser(id);});svr_uptr->InitServer();svr_uptr->Start();return 0;
}

所以,后续如果我们执行对应的移除方法,那我们使用的就必定是对应的um->DelUser()了

删除用户实现

void DelUser(InetAddr& id){//v1auto pos = std::remove_if(_online_user.begin(),_online_user.end(),[&id](std::shared_ptr<UserInterface>& user){return *user == id;});_online_user.erase(pos,_online_user.end());//v2// for(auto user : _online_user)// {//     if(*user == id)//     {//         _online_user.erase(user);//         break;//     }// }}
void PrintUser(){for(auto user : _online_user){LOG(LogLevel::DEBUG) << "在线用户->" <<user->Id();}}

这里将我们所有的列表的在线用户全都打印一遍

5.总结

四.服务器防止拷贝

#pragma once
#include <iostream>class nocopy
{
public:nocopy(){}nocopy(const nocopy &) = delete;const nocopy& operator = (const nocopy &) = delete;~nocopy(){}
};

当我们的服务器不想被拷贝,我们可以进行继承上面的nocopy的类即可

#ifndef __UDP_SERVER_HPP__
#define __UDP_SERVER_HPP__#include <iostream>
#include <string>
#include <memory>
#include <cstring>
#include <errno.h>
#include <strings.h>#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>#include "InetAddr.hpp"
#include "Common.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"using namespace LogModule;
using namespace ThreadPoolModule;const static int gsockfd = -1;
const static std::string gdefaultip = "127.0.0.1";//表示本地主机
const static uint16_t gdefaultport = 8080;using adduser_t = std::function<void(InetAddr& id)>;
using task_t = std::function<void()>;
using route_t = std::function<void (int sockfd,const std::string& message)>;
using remove_t = std::function<void(InetAddr& id)>;class nocopy
{
public:nocopy(){}nocopy(const nocopy &) = delete;const nocopy& operator = (const nocopy &) = delete;~nocopy(){}
};class UdpServer : public nocopy
{
public:UdpServer(uint16_t port = gdefaultport):_sockfd(gsockfd),_addr(port),_isrunning(false){}void InitServer(){// 1.创建套接字_sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);if (_sockfd < 0){LOG(LogLevel::FATAL) << "socket: " << strerror(errno);Die(SOCKET_ERR);}LOG(LogLevel::INFO) << "socket success, sockfd is : " << _sockfd;// 2.1 bind :: 设置进入内核中int n = ::bind(_sockfd,_addr.NetAddr(),_addr.NetAddrLen());if(n < 0){LOG(LogLevel::FATAL) << "bind: " << strerror(errno);Die(BIND_ERR);}LOG(LogLevel::INFO) << "bind success";}void RegisterService(adduser_t adduser,route_t route,remove_t remove){_adduser = adduser;_route = route;_remove = remove;}void Start(){_isrunning = true;while(true){char inbuffer[1024];struct sockaddr_in peer;socklen_t len = sizeof(peer);ssize_t n = ::recvfrom(_sockfd,inbuffer,sizeof(inbuffer)-1,0,CONV(&peer),&len);if(n > 0){//1.消息内容 && 2.谁给我发的InetAddr cli(peer);inbuffer[n] = 0;std::string message;if(strcmp(inbuffer,"Quit!") == 0){//移除观测者_remove(cli);message = cli.Addr() + "# " + "我走了,你们聊!";}else{//2.新增用户_adduser(cli);message = cli.Addr() + "# " + inbuffer;}//3.新增转发模块task_t task = std::bind(UdpServer::_route,_sockfd,message);ThreadPool<task_t>::getInstance()->Equeue(task);std::string clientinfo = cli.Ip() + " : " + std::to_string(cli.Port()) + " # " + inbuffer;LOG(LogLevel::DEBUG) << clientinfo;std::string echo_string = "echo# ";echo_string += inbuffer;::sendto(_sockfd,echo_string.c_str(),echo_string.size(),0,CONV(&peer),sizeof(peer));}}_isrunning = false;}~UdpServer(){if(_sockfd > gsockfd){::close(gsockfd);}}private:int _sockfd;InetAddr _addr;bool _isrunning; //服务器运行状态//新增用户adduser_t _adduser;//移除用户remove_t _remove;//数据转发route_t _route;
};#endif
http://www.dtcms.com/a/602106.html

相关文章:

  • 【Git Merge branch】Git 合并提交(Merge Commit)的成因与清理:从本地修复到安全重写历史
  • 视觉学习篇——理清机器学习:分类、流程与技术家族的关系
  • 个人 网站备案 幕布wordpress黑群
  • 机器学习日报17
  • 沛县网站建设wordpress 标签 标题
  • 数字孪生IOC:让数据中心运维从“被动响应”到“主动预警”的智能革命
  • 长春作网站建设的公司wordpress上传到服务器发布
  • 炭黑仪:高精度材料分析的关键工具
  • C++条件判断与循环(一)(算法竞赛)
  • 电商网站维护网络销售是什么样的工作
  • 怎么给网站添加图标网页浏览器cookie
  • 贵州安顺建设主管部门网站信息可视化网站
  • 【计算几何 | 那忘算 11】旋转卡壳(附详细证明)
  • 动作识别3——mmpose和mmaction2
  • 潍坊做网站优化网站设计项目
  • 2025企业可观测平台选型指南:聚焦核心能力,构建面向未来的观测体系
  • 郑州网站建设最低价鼓楼徐州网站开发
  • java开源Socket.io服务器端长链接通信解决方案
  • 牛客2025秋季算法编程训练联赛4-基础组
  • 视频类网站怎么做软件开发专业技能
  • 具身智能-一文详解视觉-语言-动作(VLA)大模型1.前言2.VLA的进化之路:从单兵作战到三位一体3.拆解VLA的大脑:核心组件全解析 预训练视觉表征
  • 空口协议栈的介绍及CA对其的影响
  • 网站建设制作优化推广类电商文案
  • 网站空间购买价格电子商务以后能干什么
  • C语言编译预处理 | 探索C语言编译过程中的预处理环节
  • kubernetes(k8s)-扩缩容(工作负载HPA、节点)
  • 广告设计网站官网北京小程序定制开发
  • 做网站怎样收费的怎样更换网站模板
  • 狸窝转换器将MP4格式视频转换为以下格式后的大小对比:RM、RMVB、AVI、MKV、WMV、VOB、MOV、FLV、ASF、DAT、3GP、MPG、MPEG
  • 【QT/C++】Qt样式设置之CSS知识(系统性概括)