基于Socket简单的UDP网络程序

04-09 1133阅读

⭐小白苦学IT的博客主页

⭐初学者必看:Linux操作系统入门

⭐代码仓库:Linux代码仓库

❤关注我一起讨论和学习Linux系统

1.前言

网络编程前言

网络编程是连接数字世界的桥梁,它让计算机之间能够交流信息,为我们的生活和工作带来便利。从简单的网页浏览到复杂的分布式系统,网络编程无处不在。

然而,网络编程涉及诸多复杂概念和技术,如IP地址、端口号、Socket、TCP/UDP协议等,需要我们深入学习和掌握。同时,网络环境的复杂性、数据安全性等问题也带来了挑战。

但正是这些挑战,让网络编程充满了无限可能。掌握网络编程技术,我们可以开发出各种创新应用,为人们提供更高效、智能的服务。

本文旨在介绍网络编程的Socket编程接口及其技术,分享实用经验,帮助读者打下坚实的网络编程基础。

1.socket编程接口

socket常见API

// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,socklen_t address_len);
// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);
// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,socklen_t* address_len);
// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

sockaddr结构

socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、IPv6,以及后面要谈的UNIX DomainSocket. 然而, 各种网络协议的地址格式并不相同.

基于Socket简单的UDP网络程序

  • IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位地址类型, 16位端口号和32位IP地址。
  • IPv4、IPv6地址类型分别定义为常数AF_INET、AF_INET6. 这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容。
  • socket API可以都用struct sockaddr *类型表示, 在使用的时候需要强制转化成sockaddr_in; 这样的好处是程序的通用性, 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体指针做为参数。

    sockaddr 结构 

    sockaddr 是一个通用的套接字地址结构,它用于表示各种类型的套接字地址。但是,sockaddr 结构本身并不包含足够的信息来确定地址的类型,因此它通常被更具体的结构(如 sockaddr_in)所替代。sockaddr 结构的主要作用是为不同的地址结构提供一个统一的接口。

    基于Socket简单的UDP网络程序

    • 通用性:sockaddr是一个通用的套接字地址结构,设计初衷是为了能够表示各种类型的套接字地址,包括IPv4、IPv6以及其他可能的地址类型。这种通用性使得sockaddr能够作为许多网络编程函数的参数,如bind、connect、recvfrom、sendto等,用于指明地址信息。
    • 扩展性:通过定义sa_family字段,sockaddr能够区分不同类型的地址结构。这使得在未来引入新的地址类型时,不需要修改现有函数的接口,只需定义新的地址结构并设置相应的sa_family即可。

      sockaddr_in 结构

      sockaddr_in 是 sockaddr 结构的一个特例,用于表示 IPv4 地址和端口号。它包含了 IP 地址和端口号的信息,以及地址族和协议信息。

      基于Socket简单的UDP网络程序

      • IPv4特化:尽管sockaddr具有通用性,但在实际编程中,特别是在处理IPv4地址时,直接使用sockaddr结构会显得过于复杂和冗余。sockaddr_in结构是针对IPv4地址设计的,它包含了IPv4地址和端口号等必要信息,并且以更直观和易于操作的方式呈现这些信息。
      • 便利性:sockaddr_in提供了专门的字段来存储IPv4地址(sin_addr)和端口号(sin_port),这使得在处理IPv4网络编程任务时更加方便和高效。同时,通过类型转换,sockaddr_in结构可以很容易地转换为sockaddr结构,从而与需要sockaddr参数的函数兼容。

        in_addr结构 

        in_addr 结构用于表示一个 IPv4 地址。它通常与 sockaddr_in 结构一起使用,作为 sin_addr 字段的类型。

        基于Socket简单的UDP网络程序

        在这个结构中,s_addr 是一个无符号长整数,表示 IPv4 地址。在实际使用中,我们通常不会直接操作这个长整数,而是使用诸如 inet_pton 和 inet_ntop 这样的函数来将点分十进制格式的 IP 地址(如 "192.168.1.1")转换为 in_addr 结构,或者将 in_addr 结构转换为点分十进制格式的字符串。 

        • IPv4地址表示:in_addr结构专门用于表示IPv4地址。它通过一个无符号长整数(s_addr)来存储IPv4地址,这种表示方式在网络编程中非常常见。尽管IPv4地址通常以点分十进制的形式表示(如192.168.1.1),但在内部处理和网络传输时,它们通常被转换为这种整数形式。
        • 转换方便:in_addr结构使得在点分十进制格式和内部整数格式之间转换IPv4地址变得相对简单。通过调用如inet_pton和inet_ntop这样的函数,可以轻松实现这两种格式之间的转换,从而方便网络编程中的地址处理。

          总结一下就是:

          • sockaddr 是一个通用的套接字地址结构,用于表示各种类型的地址。
          • sockaddr_in 是 sockaddr 的一个特例,用于表示 IPv4 地址和端口号。
          • in_addr 用于表示 IPv4 地址。

            这三种结构的存在是为了满足不同网络编程需求和提高编程效率。sockaddr提供了通用性和扩展性,sockaddr_in则针对IPv4地址提供了更直观和便利的操作方式,而in_addr则专门用于表示和转换IPv4地址。在实际编程中,根据具体需求选择合适的结构进行处理,可以提高代码的可读性和可维护性。

            2.简单UDP的echo服务器(代码实现)

            封装 UdpSocket

            UdpServer.hpp

            默认ip用 0.0.0.0

            端口:8080

            对udp服务器进行封装:

            #pragma once
            #include "Log.hpp"
            #include 
            #include 
            #include 
            #include 
            #include 
            #include 
            #include 
            #include
            #include
            using func_t = std::function;
            uint16_t defaultport = 8080;
            std::string defaultip = "0.0.0.0";
            const int size = 1024;
            enum
            {
                SOCKET_ERR = 1,
                BIND_ERR
            };
            class UdpServer
            {
            public:
                UdpServer(const uint16_t &port = defaultport, const std::string &ip = defaultip)
                    :_sockfd(-1), _port(port), _ip(ip),_isrunning(false)
                {
                }
                void Init()
                {
                    //1.创建udp socket
                    _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
                    if (_sockfd uint32_t 2.uint32_t 必须是网络序列的
                    //local.sin_addr.s_addr = htonl(INADDR_ANY);
                    if(bind(_sockfd,(const struct sockaddr *)&local,sizeof(local))
VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]