【网络】UDP网络服务器

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

代码的整体逻辑:

UDP服务端:udpServer.cc(服务端的调用),udpServer.hpp(服务端的实现)

UDP客户端:udpClient.cc(客户端的调用),udpClient.hpp(客户端的实现)

1.udp服务端

服务端:1.初始化服务器 2.启动服务器 

作为一款服务器:要有自己的服务端口号uint16_t _port,同时网络服务器需要有对应的string _ip地址,文件描述符_sockfd:进行各种各样的数据通信,在类内进行读写操作。对于ip地址的类型:字符串型只在我们用户层作为参数传递,传递的IP格式为" 127.0.0.1 "这种格式的IP称之为“点分十进制"IP,这样的IP是字符串,可读性高,但是仅仅在我们用户层使用,但是在网络通信的过程中IP是需要转换为 uint32_t 类型,这时候需要调用相关的接口转换为网络通信使用的的IP风格。

一.初始化服务器

初始化服务器服务器包括:创建套接字和绑定端口号和IP

【网络】UDP网络服务器

参数据数domain:域,未来套接字是进行网络通信还是本地通信,主要使用下面这两种 :
AF_UNIX, AF_LOCAL 
AF_INET 
参数type:套接字提供服务的类型,如SOCK_STREAM:流式服务TCP策略,SOCK_DGRAM:数据报服务,UDP策略

参数protocol:缺省为0,可由前两个类型由系统决定并填充

返回值:失败返回-1,成功返回文件描述符

绑定端口号和IP的接口:

【网络】UDP网络服务器

参数sockfd:文件描述符进行通信,也就是调用socket的返回值

参数addr:利用struct sockaddr_in强转

参数addrlen:结构体的长度

返回值:成功返回0,失败返回-1

这里需要定义一个sockaddr_in结构体并填充数据,然后传递进去

【网络】UDP网络服务器

 sockaddr_in结构体的内部成员:

struct sockaddr_in
  {
    __SOCKADDR_COMMON (sin_);
    in_port_t sin_port;			/* Port number.  */
    struct in_addr sin_addr;		/* Internet address.  */

    /* Pad to size of `struct sockaddr'.  */
    unsigned char sin_zero[sizeof (struct sockaddr) -
			   __SOCKADDR_COMMON_SIZE -
			   sizeof (in_port_t) -
			   sizeof (struct in_addr)];
  };

在结构体内部:首先填充协议家族,给别人发消息未来还要从对方接收消息,所以需要将自己的port和IP填充进去,port需要由主机序列转为网络序列,因为初始传来的ip是string类型的所以IP需要由点分十进制转为整数然后再转为网络序列。

一款网络服务器不建议指明一个IP,也就是不要显示地绑定IP,服务器IP可能不止一个,如果只绑定一个明确的IP,最终的数据可能用别的IP来访问端口号,访问不出来,所以真实的服务器IP一般采用INADDR_ANY(全0,任意地址)代表任意地址bind
 

初始化服务器的代码:

	void initServer()
        {
            //1.创建套接字
            _sockfd = socket(AF_INET,SOCK_DGRAM,0);
            if(_sockfd == -1)
            {
                cerr<<"socket error: "<<errno<<" : "<<strerror(errno)<<endl;
                exit(SOCKET_ERR);
            }
            cout << "socket success " << " : " << _sockfd << endl;
            //2.绑定端口号port,ip
            struct sockaddr_in local;//定义了一个变量
            //结构体清空
            bzero(&local,sizeof(local));
            local.sin_family = AF_INET;//协议家族
            local.sin_port=htons(_port);//给别人发消息,port和ip也要发给对方,需要大小端转换

            //local.sin_addr.s_addr = inet_addr(_ip.c_str());//1.ip转成整数 2.整数要转成网络序列:htonl();
            local.sin_addr.s_addr=inet_addr(INADDR_ANY);

            int n = bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
            if(n==-1)
            {
                cerr<<"bind error: "<<errno<<" : "<<strerror(errno)<<endl;
                exit(BIND_ERR);
            }
           
        }

二.启动服务器

服务器只要启动了就是不断地在接收并处理数据最后有必要时还要给客户端返回一些数据,所以要一直循环的运行,服务器是一个常驻内存的进程。

接收数据:

#include <sys/types.h>
#include <sys/socket.h>

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

sockfd:特定的套接字,buf:读取到特定缓冲区,len:多长

flags:读取的方式,默认为0,阻塞读取

src_addr:收到消息除了本身,还得知道是谁发的,输入输出型参数,返回对应的消息内容是从哪一个client发来的,len:大小是多少

返回-1表示失败,成功返回字节数

创建一个类型为sockaddr_in 的结构体,未来根据这个结构体可以得知发送数据主机的IP和端口号

        void start()
        {
            
            char buffer[gnum];
            for(;;)
            {
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);
                ssize_t s = recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);
                
                if(s>0)
                {
                    buffer[s] = 0;
                    string clientip = inet_ntoa(peer.sin_addr);//1.网络序列转化成本地序列2.4字节整数IP转化成点分十进制
                    uint16_t clientport = ntohs(peer.sin_port);
                    string message = buffer;
                    cout<<clientip<<"["<<clientport<<"]# "<<message<<endl;
                }

            }
        }

三.上层的调用

#include "udpServer.hpp"
#include <memory>

using namespace std;
using namespace Server;

static void Usage(string  proc)
{
    cout<<"\nUsage:\n\t"<<proc<<"  local_port\n\n";
}
//  ./udpServer  port
int main(int argc,char*argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        exit(1);
    }
    uint16_t port = atoi(argv[1]);

    std::unique_ptr<udpServer> usvr(new udpServer(port));

    usvr->initServer();
    usvr->start();
    return 0;
}

2.udp客户端

1.客户端上层的调用

启动客户端方法为  :  ./udpClient server_ip server_port,客户端想连接服务器,必须得知道对方的IP(公网IP)和端口号调用逻辑如下:

#include "udpClient.hpp"
#include <memory>

using namespace Client;
static void Usage(string  proc)
{
    cout<<"\nUsage:\n\t"<<proc<<" server_ip server_port\n\n";
}
//./udpCleint server_ip server_port
int main(int argc,char*argv[])
{
    if(argc!=3)
    {
        Usage(argv[0]);
        exit(1);
    }
    string serverip = argv[1];
    uint16_t serverport = atoi(argv[2]);
    unique_ptr<udpClient> ucli(new udpClient(serverip,serverport));
    ucli->initClient();
    ucli->run();
    return 0;
}

2.初始化客户端

初始化客户端需要创建套接字,客户端需要端口,但是不重要,自己有端口号就可以,不需要显示的绑定会由操作系统帮助我们找到一个没有被绑定的端口号并绑定。

3.启动客户端

#include <sys/types.h>
#include <sys/socket.h>

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

sockfd:哪个套接字,buf:缓冲区,len:长度,flags:0,有数据就发,没数据就阻塞

dest_addr:这个结构体也是由struct sockaddr_in强转,向谁发,填充对方的IP和端口

addrlen:没有指针,输入型参数

代码实现:

	    void run()
        {
            struct sockaddr_in server;
            memset(&server,0,sizeof(server));
            server.sin_family = AF_INET;
            server.sin_addr.s_addr = inet_addr(_serverip.c_str());
            server.sin_port = htons(_serverport);
            string message;
            while(!_quit)
            {
                cout<<"Please Enter# ";
                cin>>message;

                //发送给远端服务器
                sendto(_sockfd,message.c_str(),message.size(),0,(struct sockaddr*)&server,sizeof(server));
            }
        }

3.测试服务器

【网络】UDP网络服务器

 【网络】UDP网络服务器

 IP 为 127.0.0.1是本地回环地址,通俗的讲,就是我们在主机上发送给127开头的IP地址的数据包会被发送的主机自己接收,根本传不出去,外部设备也无法通过回环地址访问到本机,数据只是在本机内协议贯穿,根本不会到达物理层,用来服务器代码的测试。

4.整体代码

//udpServer.hpp
#pragma once
#include <iostream>
#include <string>
#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>
namespace Server
{
    using namespace std;
    static const string defaultIP = "0.0.0.0";
    static const int gnum = 1024;
    enum {USAGE_ERR = 1,SOCKET_ERR,BIND_ERR};

    class udpServer
    {
    public:
        udpServer(const uint16_t&port,const string&ip = defaultIP)
        :_port(port),_ip(ip),_sockfd(-1)
        {}
        void initServer()
        {
            //1.创建套接字
            _sockfd = socket(AF_INET,SOCK_DGRAM,0);
            if(_sockfd == -1)
            {
                cerr<<"socket error: "<<errno<<" : "<<strerror(errno)<<endl;
                exit(SOCKET_ERR);
            }
            cout << "socket success " << " : " << _sockfd << endl;
            //2.绑定端口号port,ip
            struct sockaddr_in local;
            bzero(&local,sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port=htons(_port);
            //local.sin_addr.s_addr = inet_addr(_ip.c_str());
            local.sin_addr.s_addr = htons(INADDR_ANY);
            int n = bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
            if(n==-1)
            {
                cerr<<"bind error: "<<errno<<" : "<<strerror(errno)<<endl;
                exit(BIND_ERR);
            }
        }
        void start()
        {
            char buffer[gnum];
            for(;;)
            {
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);
                ssize_t s = recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);
                if(s>0)
                {
                    buffer[s] = 0;
                    string clientip = inet_ntoa(peer.sin_addr);//1.网络序列转化成本地序列2.4字节整数IP转化成点分十进制
                    uint16_t clientport = ntohs(peer.sin_port);
                    string message = buffer;
                    cout<<clientip<<"["<<clientport<<"]# "<<message<<endl;
                }
            }
        }
    private:
        uint16_t _port;//端口号
        string _ip;//ip地址
        int _sockfd;//文件描述符
    };
}

//udpServer.cc
#include "udpServer.hpp"
#include <memory>
using namespace std;
using namespace Server;
static void Usage(string  proc)
{
    cout<<"\nUsage:\n\t"<<proc<<"  local_port\n\n";
}
//  ./udpServer  port
int main(int argc,char*argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[1]);
    std::unique_ptr<udpServer> usvr(new udpServer(port));
    usvr->initServer();
    usvr->start();
    return 0;
}


//udpClient.hpp
#pragma once
#include <iostream>
#include <string>
#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>
namespace Client
{
    using namespace std;
    class udpClient
    {

    public:
        udpClient(const string&serverip,const uint16_t &serverport)
        :_serverip(serverip),_serverport(serverport),_sockfd(-1),_quit(false)
        {}
        void initClient()
        {
            //客户端创建socket
            _sockfd = socket(AF_INET,SOCK_DGRAM,0);
            if(_sockfd == -1)
            {
                cerr<<"socket error: "<<errno<<" : "<<strerror(errno)<<endl;
                exit(2);
            }
            cout<<"socket success "<<" : "<<_sockfd<<endl;
        }
        void run()
        {
            struct sockaddr_in server;
            memset(&server,0,sizeof(server));
            server.sin_family = AF_INET;
            server.sin_addr.s_addr = inet_addr(_serverip.c_str());
            server.sin_port = htons(_serverport);
            string message;
            while(!_quit)
            {
                cout<<"Please Enter# ";
                cin>>message;
                sendto(_sockfd,message.c_str(),message.size(),0,(struct sockaddr*)&server,sizeof(server));
            }
        }
    private:
        int _sockfd;
        string _serverip;
        uint16_t _serverport;
        bool _quit;
    };
}

//udpClient.cc
#include "udpClient.hpp"
#include <memory>
using namespace Client;
static void Usage(string  proc)
{
    cout<<"\nUsage:\n\t"<<proc<<" server_ip server_port\n\n";
}
//./udpCleint server_ip server_port
int main(int argc,char*argv[])
{
    if(argc!=3)
    {
        Usage(argv[0]);
        exit(1);
    }
    string serverip = argv[1];
    uint16_t serverport = atoi(argv[2]);
    unique_ptr<udpClient> ucli(new udpClient(serverip,serverport));
    ucli->initClient();
    ucli->run();
    return 0;
}

makefile文件:

【网络】UDP网络服务器文章来源地址https://www.toymoban.com/news/detail-475569.html

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

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

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

相关文章

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

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

    2024年02月15日
    浏览(49)
  • 简单的UDP网络程序·续写(后端服务器)

    该文承接文章 简单的UDP网络程序 对于客户端和服务端的基本源码参考上文,该文对服务器润色一下,并且实现几个基本的业务服务逻辑 目录 demo1 第一个功能:字典翻译 初始化字典 测试代码:打印 字符串分割 客户端修改 成品效果 字典热加载 signal demo2 远端命令行解析 p

    2024年02月09日
    浏览(45)
  • 【socket编程】TCP服务器、UDP服务器、本地套接字【C语言代码实现】

    目录 0. 准备知识 0.1 大小端概念 0.2 网络字节序和主机字节序的转换 0.3 点分十进制串转换(IP地址转换函数) 0.4 IPV4结构体:(man 7 ip) 0.5 IPV6套接字结构体:(man 7 ipv6) 0.6 通用套接字结构体 1. 网络套接字函数 1.1 socket 1.2 connect 1.3 bind 1.4 listen 1.5 accept 1.6 端口复用 2. 包裹函

    2024年02月07日
    浏览(54)
  • Linux网络编程:线程池并发服务器 _UDP客户端和服务器_本地和网络套接字

    文章目录: 一:线程池模块分析 threadpool.c 二:UDP通信 1.TCP通信和UDP通信各自的优缺点 2.UDP实现的C/S模型 server.c client.c 三:套接字  1.本地套接字 2.本地套 和 网络套对比 server.c client.c threadpool.c   server.c client.c server.c client.c

    2024年02月11日
    浏览(66)
  • 【网络编程】网络套接字&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)
  • 网络编程套接字(二)之UDP服务器简单实现

    目录 一、服务端UdpServer 1、udp_server.hpp 1、服务器的初始化 2、服务器的运行 2、udp_server.cc 二、客户端UdpClient udp_client.cc 三、完整代码 首先,我们在该文件中,将服务器封装成一个类,而作为一款服务器,必须要有自己的端口号,同时网络服务器需要有对应的IP地址,文件描述

    2024年04月16日
    浏览(57)
  • 【云服务器】关于UDP/TCP跨平台网络通信服务器无响应的情况及解决办法

    本篇文章仅为了记录我在跨平台进行udp通信的时候遇到的问题及解决办法 进行udp网络通信的时候,我用腾讯云服务器作服务端,windows本机作客户端,在进行连接的时候,当我在客户端向服务端发送消息的时候,服务器端接收不到消息(安全组已经配置) 当执行上述命令出现

    2024年02月10日
    浏览(44)
  • 【计算机网络】网络编程套接字&UDP服务器客户端的简单模拟

    需要云服务器等云产品来学习Linux的同学可以移步/–腾讯云–/官网,轻量型云服务器低至112元/年,优惠多多。(联系我有折扣哦) 每台主机都有自己的IP地址,当数据在进行通信的时候,除了要发送的数据外,在报头里面还要包含发送方的IP和接收方的IP,这里发送方的IP就

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

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

    2023年04月16日
    浏览(55)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包