day-04 基于UDP的服务器端/客户端

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

一.理解UDP

day-04 基于UDP的服务器端/客户端,# 网络编程,udp,网络协议,网络

(一)UDP套接字的特点

UDP套接字具有以下特点:

  • 无连接性:UDP是一种无连接的协议,这意味着在发送数据之前,不需要在发送方和接收方之间建立连接。每个UDP数据包都是独立的,它们可以独立地发送和接收,而不需要维护连接状态。

  • 不可靠性:UDP是一种不可靠的协议,这意味着它不提供数据传输的可靠性保证。UDP数据包在发送过程中可能会丢失、重复、乱序或损坏,而UDP协议本身不提供任何机制来检测和纠正这些问题。因此,应用程序需要自行处理这些问题。

  • 高效性:由于UDP不需要建立连接和维护连接状态,它的开销比TCP更小,传输效率更高。UDP适用于那些对实时性要求较高,但对数据可靠性要求相对较低的应用场景,如音频和视频流传输。

  • 面向数据报:UDP是一种面向数据报的协议,每个UDP数据包都是一个独立的数据报,具有固定的大小。UDP数据包的大小限制为64KB,超过这个大小的数据需要进行分片和重新组装。

  • 支持多播和广播:UDP支持多播和广播功能,可以将数据同时发送给多个接收方。多播是一种一对多的通信方式,广播是一种一对所有的通信方式。

        总的来说,UDP套接字具有无连接性、不可靠性、高效性、面向数据报和支持多播和广播等特点。它适用于那些对实时性要求较高,但对数据可靠性要求相对较低的应用场景。

(二)UDP内部工作原理

UDP的内部工作原理如下:

  • 创建套接字:在UDP通信之前,需要创建UDP套接字。套接字是一个网络通信的端点,用于发送和接收数据。通过调用操作系统提供的套接字API,可以创建一个UDP套接字。

  • 绑定端口:在创建UDP套接字后,需要将套接字绑定到一个特定的端口上。这样,其他应用程序就可以通过指定该端口来与UDP套接字进行通信。

  • 发送数据:要发送数据,应用程序将数据写入UDP套接字的发送缓冲区。操作系统将从发送缓冲区中获取数据,并将其封装成UDP数据包。然后,操作系统将UDP数据包发送到目标IP地址和端口。

  • 接收数据:要接收数据,应用程序需要监听UDP套接字。当有UDP数据包到达时,操作系统将从网络中接收数据包,并将其放入UDP套接字的接收缓冲区。应用程序可以从接收缓冲区中读取数据。

  • 处理数据:应用程序可以从接收缓冲区中读取数据,并对数据进行处理。由于UDP是无连接的协议,每个UDP数据包都是独立的,应用程序需要自行处理数据包的顺序、丢失、重复和损坏等问题。

  • 关闭套接字:当UDP通信结束时,应用程序可以关闭UDP套接字,释放相关资源。

        总的来说,UDP的内部工作原理涉及创建套接字、绑定端口、发送数据、接收数据和处理数据等步骤。UDP是一种简单的协议,不提供连接状态维护和可靠性保证,但具有较低的开销和较高的传输效率。

(三)UDP的高效使用

要高效使用UDP,可以考虑以下几点:

  • 数据包大小:UDP数据包的大小限制为64KB,超过这个大小的数据需要进行分片和重新组装。为了提高传输效率,可以尽量减小数据包的大小,避免数据分片和重新组装的开销。

  • 数据压缩:对于需要传输的数据,可以考虑使用数据压缩算法进行压缩,减小数据包的大小。常见的数据压缩算法包括gzip、zlib等。

  • 并发处理:UDP是无连接的协议,每个UDP数据包都是独立的。为了提高处理效率,可以使用多线程或多进程的方式,并发处理接收到的UDP数据包。

  • 丢包处理:由于UDP是不可靠的协议,数据包在传输过程中可能会丢失。为了提高可靠性,可以在应用层实现丢包检测和重传机制。例如,可以使用序列号和确认应答的方式来检测丢包,并进行重传。

  • 超时设置:为了避免数据包长时间滞留在网络中,可以设置合适的超时时间。如果在超时时间内没有收到对应的确认应答,可以进行重传。

  • 流量控制:为了避免发送方发送过多的数据导致接收方无法及时处理,可以实现流量控制机制。例如,可以使用滑动窗口的方式控制发送方的发送速率。

  • 多播和广播:UDP支持多播和广播功能,可以将数据同时发送给多个接收方。通过合理使用多播和广播,可以提高数据传输的效率。

        总的来说,要高效使用UDP,可以考虑数据包大小、数据压缩、并发处理、丢包处理、超时设置、流量控制和多播/广播等方面的优化策略。根据具体的应用场景和需求,可以选择适合的优化方法。

二.实现基于UDP的服务器端/客户端

1.UDP中的服务器端和客户端没有连接

2.UDP服务器端和客户端均只需一个套接字

3.基于UDP的数据I/O函数

基于UDP的数据I/O函数通常使用以下两个函数:

1.sendto():该函数用于向指定的目标地址发送UDP数据包。它的函数原型如下:

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

        参数说明:

  • sockfd:UDP套接字的文件描述符。
  • buf:要发送的数据的指针。
  • len:要发送的数据的字节数。
  • flags:发送标志,通常设置为0。
  • dest_addr:目标地址的结构体指针,包括IP地址和端口号。
  • addrlen:目标地址结构体的长度。

        该函数将指定的数据发送到目标地址。如果发送成功,返回发送的字节数;如果发送失败,返回-1,并设置相应的错误码。

2.recvfrom():该函数用于从指定的源地址接收UDP数据包。它的函数原型如下:

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

        参数说明:

  • sockfd:UDP套接字的文件描述符。
  • buf:接收数据的缓冲区指针。
  • len:接收数据的最大字节数。
  • flags:接收标志,通常设置为0。
  • src_addr:源地址的结构体指针,用于存储发送方的IP地址和端口号。
  • addrlen:源地址结构体的长度。

        该函数从指定的UDP套接字接收数据,并将数据存储到指定的缓冲区中。如果接收成功,返回接收的字节数;如果接收失败,返回-1,并设置相应的错误码。

4.基于UDP的回声服务器端/客户端

uecho_server.cpp
#include <iostream>
#include <cstring>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUFFER_SIZE 1024

int main() {
    // 创建UDP套接字
    int server_socket = socket(AF_INET, SOCK_DGRAM, 0);

    // 绑定服务器地址和端口
    struct sockaddr_in server_address{};
    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = htonl(INADDR_ANY);
    server_address.sin_port = htons(8888);
    bind(server_socket, (struct sockaddr*)&server_address, sizeof(server_address));

    std::cout << "服务器已启动,等待客户端连接..." << std::endl;

    while (true) {
        // 接收数据
        char buffer[BUFFER_SIZE];
        struct sockaddr_in client_address{};
        socklen_t client_address_length = sizeof(client_address);
        ssize_t received_bytes = recvfrom(server_socket, buffer, BUFFER_SIZE, 0, (struct sockaddr*)&client_address, &client_address_length);
        buffer[received_bytes] = '\0';
        std::cout << "接收到来自客户端 " << inet_ntoa(client_address.sin_addr) << " 的数据:" << buffer << std::endl;

        // 发送数据回客户端
        sendto(server_socket, buffer, strlen(buffer), 0, (struct sockaddr*)&client_address, client_address_length);
    }

    return 0;
}
uecho_client.cpp
#include <iostream>
#include <cstring>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUFFER_SIZE 1024

int main() {
    // 创建UDP套接字
    int client_socket = socket(AF_INET, SOCK_DGRAM, 0);

    // 服务器地址和端口
    struct sockaddr_in server_address{};
    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
    server_address.sin_port = htons(8888);

    while (true) {
        // 输入要发送的数据
        char message[BUFFER_SIZE];
        std::cout << "请输入要发送的数据:";
        std::cin.getline(message, BUFFER_SIZE);

        // 发送数据到服务器
        sendto(client_socket, message, strlen(message), 0, (struct sockaddr*)&server_address, sizeof(server_address));

        // 接收服务器返回的数据
        char buffer[BUFFER_SIZE];
        socklen_t server_address_length = sizeof(server_address);
        ssize_t received_bytes = recvfrom(client_socket, buffer, BUFFER_SIZE, 0, (struct sockaddr*)&server_address, &server_address_length);
        buffer[received_bytes] = '\0';
        std::cout << "接收到服务器返回的数据:" << buffer << std::endl;
    }

    return 0;
}

5.UDP的数据传输特性和调用connect函数

        UDP存在数据边界,所以调用几次 sendto 函数去发送,就调用几次 recvfrom 函数去接收。

(1)已连接(connected)UDP套接字和未连接(unconnected)UDP套接字

        sendto 函数的传输阶段

  •         向UDP套接字注册目标IP和端口号
  •         传输数据
  •         删除UDP套接字中注册的目标地址信息

        UDP套接字默认属于未连接套接字。但在对同一主机进行通信时,过多的增删套接字中目标地址信息,很明显显得多余。所以将UDP套接字变成已连接套接字会提高效率。

三.总结

1.UDP为什么比TCP速度快?为什么TCP数据传输可靠而UDP数据传输不可靠?

        UDP和TCP不同,不进行流量控制。由于该控制涉及到套接字的连接和结束,以及整个数据收发过程,因此,TCP传输的数据是可以信赖的。相反,UDP不进行这种控制,因此无法信任数据的传输,但正因UDP不进行流量传输,所以比TCP更快。

2.UDP数据包向对方主机的UDP套接字传递过程中,IP和UDP分别负责哪些部分?

IP负责链路选择。UDP负责端到端的传输

3.UDP一般比TCP快,但更具交换数据的特点,其差异可大可小。请说明何种情况下UDP的性能优于TCP?

UDP和TCP不同,不经过连接以及断开SOCKET的过程。因此,在频繁的连接及断开的情况下,UDP的数据收发能力会凸显出更好的性能。

4.客户端TCP套接字调用connect函数时自动分配IP和端口号。UDP不调用bind函数,那什么时候分配IP和端口号?

首次调用sendto函数时,发现未分配信息,则给对应的套接字自动分配IP和端口号。

5.TCP客户端必须调用connect函数,而UDP中可以选择性调用。请问,在UDP中调用connect函数有哪些好处?

每当以UDP套接字为对象调用connect函数时,都要经过以下过程:

第一阶段:为目标UDP注册端口和IP

第二阶段:数据传输

第三阶段:删除UDP注册的IP和端口信息

其中,只要调用connect函数,就可以忽略每次传输数据时反复进行的第一阶段和第三阶段。然而,每次调用connect函数并不意味着经过连接过程,只是将IP地址和端口号指定在UDP的发送对象上。这样connect函数使用后,还可以使用write、read函数进行数据处理,而不必使用sendto、recvfrom函数。

6.收发的信息打印在控制台。

uecho_server.cpp
/********************************uchar_server.cpp***********************************/
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 30

void error_handling(const char *message);

int main(int argc, char *argv[])
{
    int serv_sock;
    char message[BUF_SIZE];
    int str_len;
    socklen_t clnt_adr_sz;
    
    struct sockaddr_in serv_adr, clnt_adr;
    if(argc != 2){
        std::cout << "Usage : " << argv[0] << " <port>" << std::endl;
        exit(1);
    }
    
    serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
    if(serv_sock == -1)
        error_handling("UDP socket creation error");
    
    memset(&serv_adr, 0, sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_adr.sin_port = htons(atoi(argv[1]));
    
    if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)
        error_handling("bind() error");
    
    clnt_adr_sz = sizeof(clnt_adr);
    while(1) 
    {
        str_len = recvfrom(serv_sock, message, BUF_SIZE, 0, 
                                (struct sockaddr*)&clnt_adr, &clnt_adr_sz);
        message[str_len] = 0;
        std::cout << "Message from client: " << message<<std::endl;

        std::cout << "Insert message(q to quit): ";
        std::cin.getline(message, sizeof(message));
        if(!strcmp(message,"q") || !strcmp(message,"Q"))    
            break;

        sendto(serv_sock, message, strlen(message), 0, 
                                (struct sockaddr*)&clnt_adr, clnt_adr_sz);
    }   
    close(serv_sock);
    return 0;
}

void error_handling(const char *message)
{
    std::cerr << message << std::endl;
    exit(1);
}
uecho_client.cpp
/********************************uchar_client.cpp***********************************/
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 30

void error_handling(const char *message);

int main(int argc, char *argv[])
{
    int sock;
    char message[BUF_SIZE];
    int str_len;
    socklen_t adr_sz;
    
    struct sockaddr_in serv_adr, from_adr;
    if(argc != 3){
        std::cout << "Usage : " << argv[0] << " <IP> <port>" << std::endl;
        exit(1);
    }
    
    sock = socket(PF_INET, SOCK_DGRAM, 0);   
    if(sock == -1)
        error_handling("socket() error");
    
    memset(&serv_adr, 0, sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = inet_addr(argv[1]);
    serv_adr.sin_port = htons(atoi(argv[2]));
    
    while(1)
    {
        std::cout << "Insert message(q to quit): ";
        std::cin.getline(message, sizeof(message));     
        if(!strcmp(message,"q") || !strcmp(message,"Q"))    
            break;
        
        sendto(sock, message, strlen(message), 0, 
                    (struct sockaddr*)&serv_adr, sizeof(serv_adr));
        adr_sz = sizeof(from_adr);
        str_len = recvfrom(sock, message, BUF_SIZE, 0, 
                    (struct sockaddr*)&from_adr, &adr_sz);

        message[str_len] = 0;
        std::cout << "Message from server: " << message<<std::endl;
    }   
    close(sock);
    return 0;
}

void error_handling(const char *message)
{
    std::cerr << message << std::endl;
    exit(1);
}

存在问题:文章来源地址https://www.toymoban.com/news/detail-680928.html

  • 1.在输入数据的过程中,如果时间间隔稍微长一点,就无法完整的传输数据
  • 2.无法确定是否结束传输

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

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

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

相关文章

  • 《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日
    浏览(58)
  • UDP客户端和服务器

    UDP客户端,也就是首先主动发送数据的一方,也就是发起服务请求的一方。 UDP服务器,也就是首先等待接收数据,并对接收的数据进行处理,返回计算结果的一方,也就是提供服务的一方。 在下面实验中使用到的函数 测试代码  UDP接收端(服务器) 执行代码:    实验解析 

    2024年02月13日
    浏览(88)
  • UDP通讯(服务器/客户端)

    前言:UDP通讯实现比较简单,单某些情况下也会使用,建议先看一下说明,然后运行代码感受一下。         传输层主要应用的协议模型有两种,一种是TCP协议,另外一种则是UDP协议。TCP协议在网络通信中占主导地位,绝大多数的网络通信借助TCP协议完成数据传输。但U

    2024年02月03日
    浏览(62)
  • 【网络】UDP通讯(服务器/客户端)

    前言:UDP通讯实现比较简单,单某些情况下也会使用,建议先看一下说明,然后运行代码感受一下。         传输层主要应用的协议模型有两种,一种是TCP协议,另外一种则是UDP协议。TCP协议在网络通信中占主导地位,绝大多数的网络通信借助TCP协议完成数据传输。但U

    2024年02月12日
    浏览(59)
  • 网络编程六--UDP服务器客户端

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

    2024年02月15日
    浏览(46)
  • netty构建udp服务器以及发送报文到客户端客户端详细案例

    目录 一、基于netty创建udp服务端以及对应通道设置关键 二、发送数据 三、netty中的ChannelOption常用参数说明 1、ChannelOption.SO_BACKLOG 2、ChannelOption.SO_REUSEADDR 3、ChannelOption.SO_KEEPALIVE 4、ChannelOption.SO_SNDBUF和ChannelOption.SO_RCVBUF 5、ChannelOption.SO_LINGER 6、ChannelOption.TCP_NODELAY 以上代码中

    2024年04月09日
    浏览(74)
  • Unity-UDP-客户端/服务器通信功能

    这里简单实现客户端和服务器,复杂的实现需要和前几篇文章的TCP一样,管理多个链接过来的客户端,这里只有一个。需要自己封装类似listener来管理多个链接过来的设备,每次都缓存ReceiveAsync收到消息的中的RemoteEndPoint地址端口,统一管理发送接收消息。 https://zhidao.baidu.c

    2024年02月11日
    浏览(64)
  • 【网络编程】实现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日
    浏览(58)
  • 使用Netty构建TCP和UDP服务器和客户端

    Netty是一个基于Java NIO实现的网络通信框架,提供了高性能、低延迟的网络通信能力。使用Netty构建TCP和UDP服务器和客户端非常简单,下面是一个简单的示例代码: 构建TCP服务器 构建TCP客户端 构建UDP服务器 构建UDP客户端   上述示例代码中,分别定义了一个TCP服务器、TCP客户

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

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

    2024年02月16日
    浏览(178)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包