简单的Udp服务器

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

简单的UDP网络程序

1.1 UdpServer.hpp

#pragma once

#include <iostream>
using namespace std;

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "log.hpp"
#include <strings.h>
#include <functional>
#include <cstring>
#include <unordered_map>

const static int NUM = 1024;
const static string DEFAULT_IP = "0.0.0.0";
const static uint16_t DEFAULT_PORT=8080;

using func_t=function<string(string)>;

Log log;



class UdpServer
{
public:
    UdpServer(func_t func,uint16_t port=DEFAULT_PORT,string ip = DEFAULT_IP)
        : _ip(ip), _port(port), _sockid(-1),_func(func)
    {
    }

    ~UdpServer()
    {
        if (_sockid > 0)
        {
            close(_sockid);
        }
    }

    void Init()
    {
        // 创建套接字
        _sockid = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockid < 0)
        {
            log(Fatal, "socket failed");
            exit(2);
        }
        log(Info,"create socket successful, sockid:%d",_sockid);

        // 绑定
        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        //绑定任意地址,可以接收任意发送给该主机的信息,而不是绑定一个具体的IP地址
        local.sin_addr.s_addr = INADDR_ANY;
        if (bind(_sockid, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            log(Fatal, "bind failed, errno:%d, error code:%s",errno,strerror(errno));
            exit(3);
        }
        log(Info, "Server bind successful");
    }

    //通过哈希表检查用户是否已经连上,如果没有就添加到连接的列表中
    void CheckUser(const struct sockaddr_in& client)
    {
        string clientIp=inet_ntoa(client.sin_addr);
        auto it=_online_client.find(clientIp);
        if(it==_online_client.end())
        {
            _online_client.insert({clientIp,client});
            std::cout << "[" << clientIp << ":" << ntohs(client.sin_port) << "] add to online user." << std::endl;
        }
    }

    //广播给所有人,即给所有连上该服务器的人都发送这条信息,类似于我们的微信群,
    //自己发出的信息所有人都能看见
    void BroadCast(const string& info,const string& clientip,const uint16_t& clientport)
    {
        for(const auto& it:_online_client)
        {
            string message="client";
            message+='[';
            message+="clientip:";
            message+=clientip;
            message+=' ';
            message+="clientport";
            message+=":";
            message+=to_string(clientport);
            message+="]# ";
            message+=info;

            sendto(_sockid,message.c_str(),message.size(),0,(struct sockaddr*)(&it.second),sizeof(it.second));
        }

    }

    //启动服务器
    void Run()
    {
        struct sockaddr_in client;
        socklen_t len = sizeof(client);
        bzero(&client, sizeof(client));
        char buffer[NUM];
        bzero(buffer, sizeof(buffer));
        while (true)
        {
            ssize_t s = recvfrom(_sockid, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&client, &len);
            if (s > 0)
            {
                buffer[s] = '\0';
                //cout << "client# " << buffer << endl;
                //printf("client[ip:%d,port:%d]# \n",client.sin_addr.s_addr,client.sin_port);
                char* clientip=inet_ntoa(client.sin_addr);
                //检查
                CheckUser(client);
                cout << "client[ip:"<<clientip<<" port:"<<ntohs(client.sin_port)<<"]# " << buffer << endl;

                uint16_t clientport=ntohs(client.sin_port);
                //广播给所有人
                BroadCast(buffer,clientip,clientport);
            }
            else if(s==0)
            {
                log(Warning,"client quit...");
                break;
            }
            else
            {
                log(Fatal,"recvfrom failed...");
                break;
            }

            //string ret=_func(buffer);
            //sendto(_sockid, ret.c_str(), ret.size(), 0, (struct sockaddr *)&client, len);
        }
    }

private:
    string _ip;
    uint16_t _port;
    int _sockid;
    //回调函数
    func_t _func;
    //通过IP地址映射标识一个已经连上服务器的客户端
    unordered_map<string,struct sockaddr_in> _online_client;
};

1.2 UdpClient.cc


#include <iostream>
using namespace std;

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <strings.h>
#include <pthread.h>
#include <cstring>

//   重定向:2>/dev/pts/(1,2,3,4)

//UdpClient.cc

const static int NUM = 1024;

//客户端使用手册
void Usage(string argv)
{
    cout << "\n\t"
         << "Usage:" << argv << " ServerIp ServerPort" << endl<<endl;
}

struct ThreadData
{
    int sockid;
    struct sockaddr_in server;
    string ip;
};

//读取信息
void* recver_message(void* argv)
{
    //线程分离
    pthread_detach(pthread_self());

    ThreadData* td=static_cast<ThreadData*>(argv);

    char buffer[4096];
    memset(buffer,0,sizeof(buffer));
    while(true)
    {
        struct sockaddr_in t;
        socklen_t len=sizeof(t);
        ssize_t s=recvfrom(td->sockid,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&t,&len);
        string tip=inet_ntoa(t.sin_addr);
        if(s>0)
        {
            buffer[s]='\0';
            // cout<<"server# "<<tmp<<endl;
            printf("server[ip:%s,port:%d]# %s\n",tip.c_str(),ntohs(t.sin_port),buffer);
        }
    }

    return nullptr;
}


//发送信息
void * sender_message(void* argv)
{
    pthread_detach(pthread_self());
    ThreadData* td=static_cast<ThreadData*>(argv);

    std::string welcome = td->ip;
    welcome += " comming...";
    sendto(td->sockid, welcome.c_str(), welcome.size(), 0, (struct sockaddr *)&(td->server), sizeof(td->server));

    string buffer;
    while(true)
    {
        cerr<<"Please Enter# ";
        getline(cin,buffer);
        sendto(td->sockid,buffer.c_str(),buffer.size(),0,(struct sockaddr*)(&(td->server)),sizeof(td->server));
    }
    return nullptr;
}

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }

    string ServerIp=argv[1];
    string str = argv[2];
    uint16_t ServerPort = (uint16_t)stoi(str.c_str());

    ThreadData td;

    //创建套接字
    int sockid=socket(AF_INET,SOCK_DGRAM,0);

    td.server.sin_family = AF_INET;
    td.server.sin_addr.s_addr=inet_addr(ServerIp.c_str());
    td.server.sin_port=htons(ServerPort);
    td.ip=ServerIp;
    td.sockid=sockid;
    socklen_t len=sizeof(td.server);

    pthread_t recver,sender;
    pthread_create(&recver,nullptr,recver_message,&td);
    pthread_create(&sender,nullptr,sender_message,&td);    

    while(true)
    {
        sleep(1);
    }

    close(sockid);
}

1.3 main.cc

#include <iostream>
using namespace std;
#include <string>
#include "UdpServer.hpp"
#include <vector>
#include <memory>

//服务器的启动方式
void Usage(string argv)
{
    cout << "\n\t"
         << "Usage:" << argv << " ServerPort" << endl
         << endl;
}

string func(string s)
{
    return s + " already handled\n";
}

//安全检查
bool SafeCheck(const string &cmd)
{
    //把客户端发过来的信息当作命令来解析,检查该信息是否合法
    vector<string> key_word = {"rm", "mv", "cp", "kill", "sudo", "unlink", "uninstall",
                               "yum", "top", "while"};
    for(const auto& s:key_word)
    {
        auto pos = cmd.find(s);
        if(pos!=string::npos)
        {
            return false;
        }
    }

    return true;
}

//执行指令
string ExcuteCommand(string cmd)
{
    if (!SafeCheck(cmd))
    {
        return "bad man\n";
    }
    //popen函数会自己创建子进程,创建管道,让子进程执行cmd.c_str()命令,
    //并通过管道把执行cmd命令的结果读取到FILE*的结构体对象中
    FILE *p = popen(cmd.c_str(), "r");
    if (nullptr == p)
    {
        perror("popen failed");
        exit(5);
    }
    string ret="\n";
    char buffer[4096];
    while (true)
    {
        //把执行命令后的结果按行读取出来
        char *s = fgets(buffer, sizeof(buffer) - 1, p);
        if (nullptr == s)
        {
            break;
        }
        ret += buffer;
    }
    pclose(p);
    return ret;
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(1);
    }

    string str = argv[1];
    uint16_t ServerPort = (uint16_t)stoi(str.c_str());

    unique_ptr<UdpServer> svr(new UdpServer(func, ServerPort));
    svr->Init();
    svr->Run();

    return 0;
}

1.4 makefile

.PHONY:all
all:Client Server

Client:UdpClient.cc
	g++ -o $@ $^ -std=c++11 -lpthread

Server:main.cc
	g++ -o $@ $^ -std=c++11 -lpthread

.PHONY:clean
clean:
	rm -f Client Server

1.5 log.hpp

#pragma once

#include <iostream>
using namespace std;
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string>
#include <time.h>
#include <stdarg.h>

// 日志等级
#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4

#define Screen 1
#define OneFile 2
//向多个文件打印
#define Classfile 3
#define SIZE 1024

#define LogFile "log.txt"

class Log
{
public:
    Log()
    {
        printMethod = Screen;
        path = "./log/";
    }

    void Enable(int mothod)
    {
        printMethod = mothod;
    }

    string LevelToString(int level)
    {
        switch (level)
        {
        case Info:
        {
            return "Info";
        }
        case Debug:
        {
            return "Debug";
        }
        case Warning:
        {
            return "Warning";
        }
        case Error:
        {
            return "Error";
        }
        case Fatal:
        {
            return "Fatal";
        }
        default:
        {
            return "None";
        }
        }
    }

    void printlog(int level,const string& logtxt)
    {
        switch(printMethod)
        {
        case Screen:
        {
            cout<<logtxt<<endl;
            break;
        }
        case OneFile:
        {
            PrintOneFile(LogFile,logtxt);
            break;
        }
        case Classfile:
        {
            PrintClassfile(level,logtxt);
            break;
        }
        default:
        {
            break;
        }
        }
    }

    void PrintOneFile(const string& logname,const string& logtxt)
    {
        string _logname=path+logname;
        int fd=open(_logname.c_str(),O_WRONLY|O_CREAT|O_APPEND,0666);
        if(fd<0)
        {
            perror("open fail");
            return;
        }

        write(fd,logtxt.c_str(),logtxt.size());

        close(fd);

    }

    void PrintClassfile(int level,const string& logtxt)
    {
        string filename=LogFile;
        filename+='.';
        filename+=LevelToString(level);
        PrintOneFile(filename,logtxt);
    }

    void operator()(int level,const char* format,...)
    {
        time_t t=time(nullptr);
        struct tm* ctime=localtime(&t);
        char leftbuffer[SIZE];
        snprintf(leftbuffer,SIZE,"[%s][%d-%d-%d %d:%d:%d]",LevelToString(level).c_str(),
        ctime->tm_year+1900,ctime->tm_mon+1,ctime->tm_mday,
        ctime->tm_hour,ctime->tm_min,ctime->tm_sec);

        va_list s;
        va_start(s,format);
        char rightbuffer[SIZE]={0};
        vsnprintf(rightbuffer,SIZE,format,s);
        va_end(s);


        char logtxt[SIZE*2];
        snprintf(logtxt,sizeof(logtxt),"%s %s",leftbuffer,rightbuffer);

        printlog(level,logtxt);
    }

    ~Log()
    {
    }

private:
    // 打印方法
    int printMethod;
    string path;
};

文章来源地址https://www.toymoban.com/news/detail-826696.html

到了这里,关于简单的Udp服务器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 网络编程六--UDP服务器客户端

    UDP(User Datagram Protocol)称为用户数据报协议,是一种无连接的传输协议。 UDP的主要应用在即使丢失部分数据,也不影响整体效果的场景。例实时传输视频或音频时,即使丢失部分数据,也不会影响整体效果,只是会有轻微的画面抖动或杂音。 UDP服务器/客户端不像TCP那样,交

    2024年02月15日
    浏览(49)
  • [网络编程]UDP协议,基于UDP协议的回显服务器

    目录 1.UDP协议介绍 2.UDP协议在Java中的类 2.1DatagramSocket类 2.2DatagramPacket 3.回显服务器 3.1Sever端  3.2Client端   UDP协议是一种网络协议,它是无连接的,全双工,并且是面向数据报,不可靠的一种协议。 常用于在线视频播放,游戏这种实时性要求比较高的应用。或者无需可靠传输

    2024年01月22日
    浏览(56)
  • 【网络编程】网络套接字&udp通用服务器和客户端

    端口号(port)是传输层协议的内容: 端口号是一个2字节16位的整数(uint16) 端口号用来标识主机上的一个进程 IP地址+port能够标识网络上的某一台主机和某一个进程 一个端口号只能被一个进程占用 此处我们先对TCP(Transmission Control Protocol 传输控制协议) 有一个直观的认识,后面再

    2024年02月16日
    浏览(214)
  • 【网络编程】实现UDP/TCP客户端、服务器

    需要云服务器等云产品来学习Linux的同学可以移步/--腾讯云--/--阿里云--/--华为云--/官网,轻量型云服务器低至112元/年,新用户首次下单享超低折扣。   目录 一、UDP 1、Linux客户端、服务器 1.1udpServer.hpp 1.2udpServer.cc 1.3udpClient.hpp 1.4udpClient.cc 1.5onlineUser.hpp 2、Windows客户端 二、T

    2024年02月06日
    浏览(61)
  • [Linux] 网络编程 - 初见TCP套接字编程: 实现简单的单进程、多进程、多线程、线程池tcp服务器

    网络的上一篇文章, 我们介绍了网络变成的一些重要的概念, 以及 UDP套接字的编程演示. 还实现了一个简单更简陋的UDP公共聊天室. [Linux] 网络编程 - 初见UDP套接字编程: 网络编程部分相关概念、TCP、UDP协议基本特点、网络字节序、socket接口使用、简单的UDP网络及聊天室实现…

    2024年02月16日
    浏览(66)
  • JavaEE & UDP简易翻译服务器 & 网络编程示例2 & TCP回显服务器,回显客户端

    禁止白嫖 T T 点点赞呗 这个翻译器主要是在上一章的回显服务器和回显客户端上进行修改 修改了计算响应的过程, 即process方法 1.1 重写方法 重写方法是Java中的一种重要手段 指在一个类的子类里,对父类的一个方法进行重新定义! 而父类的权限级别要大于等于子类~ 【除了

    2023年04月16日
    浏览(60)
  • JavaEE & UDP简易翻译服务器 & 网络编程示例2 & CTP回显服务器,回显客户端

    禁止白嫖 T T 点点赞呗 这个翻译器主要是在上一章的回显服务器和回显客户端上进行修改 修改了计算响应的过程, 即process方法 1.1 重写方法 重写方法是Java中的一种重要手段 指在一个类的子类里,对父类的一个方法进行重新定义! 而父类的权限级别要大于等于子类~ 【除了

    2023年04月16日
    浏览(55)
  • 【网络编程】基于UDP数据报实现回显服务器/客户端程序

    个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【网络编程】【Java系列】 本专栏旨在分享学习网络编程的一点学习心得,欢迎大家在评论区交流讨论💌 前言 我们如果想让应用程序进行网络通信的话,就需要调用传

    2024年02月04日
    浏览(54)
  • 【Java网络编程】基于UDP-Socket 实现客户端、服务器通信

    ​ 哈喽,大家好~我是你们的老朋友: 保护小周ღ   本期为大家带来的是网络编程的 UDP Socket 套接字,基于 UDP协议的 Socket 实现客户端服务器通信 ,Socket 套接字可以理解为是,传输层给应用层提供的一组 API,如此程序,确定不来看看嘛~~ 本期收录于博主的专栏 : JavaEE_保

    2024年02月02日
    浏览(71)
  • 《TCP/IP网络编程》阅读笔记--基于UDP的服务器端/客户端

    目录 1--TCP和UDP的主要区别 2--基于 UDP 的数据 I/O 函数 3--基于 UDP 的回声服务器端/客户端 4--UDP客户端Socket的地址分配 5--UDP存在数据边界 6--UDP已连接与未连接的设置 ① TCP 提供的是可靠数据传输服务,而 UDP 提供的是不可靠数据传输服务; ② UDP 在结构上比 TCP 更简洁,其不会

    2024年02月09日
    浏览(61)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包