如何创建基于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:然后
相关推荐
weixin_4643076311 分钟前
typedef、using、#define
算法
Nejosi_念旧12 分钟前
包文件分析器 Webpack Bundle Analyzer
前端·webpack·node.js
齐格Insight14 分钟前
优雅解决el-popover内有select时在选择后会自动关闭
前端
noravinsc41 分钟前
vue request 发送formdata
前端·javascript·vue.js
Libby博仙1 小时前
VUE3 vite下的axios跨域
前端·javascript·vue.js·前端框架·node.js
剪刀石头布啊1 小时前
Web Animation API
前端
资深前端之路1 小时前
react面试题一
前端·javascript·react.js
肖老师xy1 小时前
css动画水球图
前端·css
MiyamiKK571 小时前
leetcode_字符串 459. 重复的子字符串
算法·leetcode·职场和发展