如何创建基于udp的客户端和服务端

1.先创建好udpServer.hpp、udpServer.cc、udpClient.hpp、udpClient.cc的框架。

cpp 复制代码
#pragma once
#include <string>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <arpa/inet.h>
#include <strings.h>
#include <netinet/in.h>
#include <functional>
#include"userManager"
#include<pthread.h>
using namespace std;
const static string defaultip = "0.0.0.0";
// typedef function<void(int,string,uint16_t,string)> func_t;
typedef void (*func_t)(int,string,uint16_t,string);
class udpServer
{
public:
    udpServer(uint16_t port,func_t callback) : _port(port),_callback(callback)
    {}
    void init()
    {}
    void start()
    {}
    ~udpServer() {}

private:
    int _fd;
    uint16_t _port;
    string _ip;
    func_t _callback;
};
cpp 复制代码
#include "udpServer.hpp"
#include <memory>
#include<fstream>
using namespace std;
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cout << "输入错误,请重新输入" << endl;
    }
    uint16_t port = atoi(argv[1]);
   
    unique_ptr<udpServer> server(new udpServer(port, callback));
    server->init();
    server->start();
    return 0;
}
cpp 复制代码
#pragma once
#include <string>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <arpa/inet.h>
#include <strings.h>
#include <netinet/in.h>
#include <pthread.h>
using namespace std;
class udpClient
{
    public:
    udpClient(string serverip,uint16_t serverport):_serverip(serverip),_serverport(serverport),_fd(-1)
    {}
    void init()
    {}
    void start()
    {}
    ~udpClient(){}
    private:
    int _fd;
    string _serverip;
    uint16_t _serverport;
    pthread_t reader;//这是后期需要的,看不懂接着往下看就可以
};
cpp 复制代码
#include"udpClient.hpp"
#include<memory>
using namespace std;


 int main(int argc,char* argv[])
 {
    if(argc!=3)
    {
        cout<<"输入错误,请重新输入"<<endl;
    }
    uint16_t port = atoi(argv[2]);
    string ip = argv[1];
    unique_ptr<udpClient> client(new udpClient(ip,port));
    client->init();
    client->start();
}

2.init初始化。

cpp 复制代码
 //udpServer.hpp
void init()
    {
        // 创建套接字返回fd
        _fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_fd == -1)
        {
            cerr << "socket error:" << errno << ":" << strerror(errno) << endl;
            exit(1);
        }
        // 将fd和ip,port进行绑定
        struct sockaddr_in sock;
        sock.sin_family = AF_INET;
        sock.sin_port = htons(_port);
        sock.sin_addr.s_addr = INADDR_ANY;
        int n = bind(_fd, (struct sockaddr *)&sock, sizeof(sock));
        if (n == -1)
        {
            cerr << "bind error:" << errno << ":" << strerror(errno) << endl;
            exit(2);
        }
    }
cpp 复制代码
//udpClient.hpp 
void init()
    {
        _fd = socket(AF_INET,SOCK_DGRAM,0);
        if(_fd == -1)
        {
            cout<<"socket err:"<<errno<<":"<<strerror(errno)<<endl;
            exit(1);
        }
    }

3.start发送、接收数据。

cpp 复制代码
 //udpServer.cc
void callback(int fd, string ip, uint16_t port, string messages)
{
    sockaddr_in client;
    socklen_t len = sizeof(client);
    client.sin_family = AF_INET;
    client.sin_port = htons(port);
    client.sin_addr.s_addr = inet_addr(ip.c_str());
    messages = "服务端的输出结果:"+messages;
    sendto(fd, messages.c_str(), messages.size(), 0,(struct sockaddr *)&client, len);
   
}

//udpServer.hpp
void start()
    {
        char buffer[1024];
        size_t len = sizeof(buffer);
        char writer[1024];
        struct sockaddr_in clientsock;
        socklen_t clientlen = sizeof(clientsock);
        while (1)//服务器的本质就是一个死循环
        {
            size_t n = recvfrom(_fd, buffer, len-1, 0, (struct sockaddr *)&clientsock, &clientlen);
            if (n > 0)
            {
                buffer[n]=0;
                string ip = inet_ntoa(clientsock.sin_addr); // uint32_t->string
                uint16_t port = ntohs(clientsock.sin_port);
                string messages = buffer;
                cout << ip << "[" << port << "]" << "#" << messages << endl;
                 _callback(_fd,ip,port,messages);
            }
           
        }
    }
cpp 复制代码
 //udpCLient.hpp
static void* readroutine(void* args)
    {
        pthread_detach(pthread_self());
        udpClient* c = static_cast<udpClient*>(args);
        sockaddr_in server;
        socklen_t serverlen = sizeof(server);
        while(1)
        {
            char buffer[1024];
            int len = sizeof(buffer);
            size_t n = recvfrom(c->_fd, buffer, len-1, 0, (struct sockaddr *)&server, &serverlen);
            if (n > 0)
            {
                buffer[n]=0;
                cout <<buffer << endl;
            }
        }
    }
    void start(){
        pthread_create(&reader,NULL,readroutine,(void*)this);
        char buffer[1024];
        struct sockaddr_in serveraddr;
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_port = htons(_serverport);
        serveraddr.sin_addr.s_addr = inet_addr(_serverip.c_str());
        while(1)
        {
            cin>>buffer;
            ssize_t n = sendto(_fd,buffer,sizeof(buffer),0,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
            if(n == -1)
            {
                cout<<"sendto err:"<<errno<<":"<<strerror(errno)<<endl;
            }
        }
    }

完整代码:

udpClient.cc

cpp 复制代码
#include"udpClient.hpp"
#include<memory>
using namespace std;


 int main(int argc,char* argv[])
 {
    if(argc!=3)
    {
        cout<<"输入错误,请重新输入"<<endl;
    }
    uint16_t port = atoi(argv[2]);
    string ip = argv[1];
    unique_ptr<udpClient> client(new udpClient(ip,port));
    client->init();
    client->start();
}

udpClient.hpp

cpp 复制代码
#pragma once
#include <string>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <arpa/inet.h>
#include <strings.h>
#include <netinet/in.h>
#include <pthread.h>
using namespace std;
class udpClient
{
    public:
    udpClient(string serverip,uint16_t serverport):_serverip(serverip),_serverport(serverport),_fd(-1)
    {}
    void init()
    {
        _fd = socket(AF_INET,SOCK_DGRAM,0);
        if(_fd == -1)
        {
            cout<<"socket err:"<<errno<<":"<<strerror(errno)<<endl;
            exit(1);
        }
    }
    static void* readroutine(void* args)
    {
        pthread_detach(pthread_self());
        udpClient* c = static_cast<udpClient*>(args);
        sockaddr_in server;
        socklen_t serverlen = sizeof(server);
        while(1)
        {
            char buffer[1024];
            int len = sizeof(buffer);
            size_t n = recvfrom(c->_fd, buffer, len-1, 0, (struct sockaddr *)&server, &serverlen);
            if (n > 0)
            {
                buffer[n]=0;
                cout <<buffer << endl;
            }
        }
    }
    void start(){
        pthread_create(&reader,NULL,readroutine,(void*)this);
        char buffer[1024];
        struct sockaddr_in serveraddr;
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_port = htons(_serverport);
        serveraddr.sin_addr.s_addr = inet_addr(_serverip.c_str());
        while(1)
        {
            cin>>buffer;
            ssize_t n = sendto(_fd,buffer,sizeof(buffer),0,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
            if(n == -1)
            {
                cout<<"sendto err:"<<errno<<":"<<strerror(errno)<<endl;
            }
        }
    }
    ~udpClient(){}
    private:
    int _fd;
    string _serverip;
    uint16_t _serverport;
    pthread_t reader;
};

udpServer.cc

cpp 复制代码
#include "udpServer.hpp"
#include <memory>
#include<fstream>
using namespace std;
// 处理方式1:翻译软件
unordered_map<string, string> dictmap;
void to_map(string messages);
// 1.打开文件,按行读取
void openfile()
{
    ifstream in;
    in.open("dict.txt",std::ios::binary);
    if(in.is_open())
    {
        std::string line;
        while(getline(in,line))
        {
            to_map(line);
        }
    }
}
// 2.按行存到map中
void to_map(string messages)
{
    size_t pos = messages.find(":");
    dictmap.insert(make_pair(messages.substr(0, pos), messages.substr(pos + 1)));
}
// 3.接收传来的message并通过map查询
void translate(int fd, string ip, uint16_t port, string messages)
{
    sockaddr_in client;
    socklen_t len = sizeof(client);
    client.sin_family = AF_INET;
    client.sin_port = htons(port);
    client.sin_addr.s_addr = inet_addr(ip.c_str());
    if (dictmap.find(messages) != dictmap.end())
    {
        cout<<"messages:"<<dictmap[messages].c_str()<<endl;
        sendto(fd, dictmap[messages].c_str(), dictmap[messages].size(), 0,(struct sockaddr *)&client, len);
    }
    else
    {
        string mes = "无结果";
        sendto(fd, mes.c_str(), mes.size(),0, (struct sockaddr *)&client, len);
    }
}
// 4.test测试文件有没有加载成功
void printdict()
{
    for (auto e : dictmap)
    {
        cout << e.first << ":" << e.second << endl;
    }
}
// 处理方式2:群聊
onlineUser onlineuser;
void group_chat(int fd, string ip, uint16_t port, string messages)
{
    // 将客户端的信息传进来
    onlineuser.addOnlineUser(ip, port);
    onlineuser.broadcastMessage(fd, ip, port, messages);
}
// 处理方式3:最简单版本收到什么原样返回
void callback(int fd, string ip, uint16_t port, string messages)
{
    sockaddr_in client;
    socklen_t len = sizeof(client);
    client.sin_family = AF_INET;
    client.sin_port = htons(port);
    client.sin_addr.s_addr = inet_addr(ip.c_str());
    messages = "服务端的输出结果:"+messages;
    sendto(fd, messages.c_str(), messages.size(), 0,(struct sockaddr *)&client, len);
   
}
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cout << "输入错误,请重新输入" << endl;
    }
    uint16_t port = atoi(argv[1]);
    //openfile();
    //printdict();
    unique_ptr<udpServer> server(new udpServer(port, callback));
    server->init();
    server->start();
    return 0;
}

udpServer.hpp

cpp 复制代码
#pragma once
#include <string>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <arpa/inet.h>
#include <strings.h>
#include <netinet/in.h>
#include <functional>
#include"userManager"
#include<pthread.h>
using namespace std;


const static string defaultip = "0.0.0.0";
// typedef function<void(int,string,uint16_t,string)> func_t;
typedef void (*func_t)(int,string,uint16_t,string);
class udpServer
{
public:
    udpServer(uint16_t port,func_t callback) : _port(port),_callback(callback)
    {
    }
    void init()
    {
        // 创建套接字返回fd
        _fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_fd == -1)
        {
            cerr << "socket error:" << errno << ":" << strerror(errno) << endl;
            exit(1);
        }
        // 将fd和ip,port进行绑定
        struct sockaddr_in sock;
        sock.sin_family = AF_INET;
        sock.sin_port = htons(_port);
        sock.sin_addr.s_addr = INADDR_ANY;
        int n = bind(_fd, (struct sockaddr *)&sock, sizeof(sock));
        if (n == -1)
        {
            cerr << "bind error:" << errno << ":" << strerror(errno) << endl;
            exit(2);
        }
    }

    void start()
    {
        char buffer[1024];
        size_t len = sizeof(buffer);
        char writer[1024];
        struct sockaddr_in clientsock;
        socklen_t clientlen = sizeof(clientsock);
        while (1)
        {
            size_t n = recvfrom(_fd, buffer, len-1, 0, (struct sockaddr *)&clientsock, &clientlen);
            if (n > 0)
            {
                buffer[n]=0;
                string ip = inet_ntoa(clientsock.sin_addr); // uint32_t->string
                uint16_t port = ntohs(clientsock.sin_port);
                string messages = buffer;
                cout << ip << "[" << port << "]" << "#" << messages << endl;
                 _callback(_fd,ip,port,messages);
            }
           
        }
    }
    ~udpServer() {}

private:
    int _fd;
    uint16_t _port;
    string _ip;
    pthread_t writer;
    func_t _callback;
};

makefile

cpp 复制代码
cc=g++
.PHONY:all
all:udpClient udpServer

udpClient:udpClient.cc
	$(cc) -o $@ $^ -std=c++11 -lpthread
udpServer:udpServer.cc
	$(cc) -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:
	rm -f udpClient udpServer

以下是拓展的代码:

群聊:userManager

cpp 复制代码
#pragma once
#include <iostream>
#include <string>
#include <unordered_map>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <arpa/inet.h>
#include <strings.h>
#include <netinet/in.h>
#include <functional>
using namespace std;
class User
{
public:
    User(std::string ip, uint16_t port) : _ip(ip), _port(port)
    {
    }
    ~User()
    {
    }

    std::string _ip;
    int16_t _port;
};
class onlineUser
{
public:
    onlineUser() {}
    ~onlineUser() {}
    void addOnlineUser(std::string ip, uint16_t port)
    {
        string id = ip + "[" + std::to_string(port) + "]#";
        onUser.insert(make_pair(id, User(ip, port)));
    }
    void offOnlineUser(std::string ip, uint16_t port)
    {
        string id = ip + "[" + std::to_string(port) + "]#";
        onUser.erase(id);
    }
    void broadcastMessage(int sockfd, const string &ip, const int16_t &port, const string &messages)
    {
        string id = ip + "[" + std::to_string(port) + "]#";
        for (auto &user : onUser)
        {
            if (user.first != id)
            {
                sockaddr_in usersock;
                usersock.sin_family = AF_INET;
                usersock.sin_port = htons(user.second._port);
                usersock.sin_addr.s_addr = inet_addr(user.second._ip.c_str());
                string sendmessage = id + messages;
                sendto(sockfd, sendmessage.c_str(), sendmessage.size(), 0, (struct sockaddr *)&usersock, sizeof(usersock));
            }
        }
    }

private:
    unordered_map<string, User> onUser;
};

字典:dict.txt

cpp 复制代码
hello:你好
why:为什么
so:所以
then:然后
相关推荐
我是koten1 小时前
【运维杂谈】K8s遇到Terminating的名称空间删除不了怎么办?(解决方案亲测有效)
linux·运维·服务器·云原生·kubernetes·k8s·名称空间
GoAI7 小时前
DeepSeek Harness Memory (一)主流记忆插件总结
后端·算法·面试
卸任7 小时前
Vibe coding工具使用心得
前端·ai编程
Pniubi7 小时前
力扣54.螺旋矩阵
算法·leetcode·矩阵
brien98 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance8 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M8 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写8 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李8 小时前
一个复杂的动态表单是如何实现的
前端·设计模式