基于UDP的服务器端和客户端

2023-05-16

文章目录

  • 再谈UDP和TCP
  • 基于UDP的服务器端和客户端
    • UDP中的服务器端和客户端没有连接
    • UDP服务器端和客户端均只需1个套接字
    • 基于UDP的接收和发送函数
    • 基于UDP的回声服务器端/客户端

再谈UDP和TCP

已剪辑自: http://c.biancheng.net/view/2358.html

TCP 是面向连接的传输协议,建立连接时要经过三次握手,断开连接时要经过四次握手,中间传输数据时也要回复 ACK 包确认,多种机制保证了数据能够正确到达,不会丢失或出错。

UDP 是非连接的传输协议,没有建立连接和断开连接的过程,它只是简单地把数据丢到网络中,也不需要 ACK 包确认。

UDP 传输数据就好像我们邮寄包裹,邮寄前需要填好寄件人和收件人地址,之后送到快递公司即可,但包裹是否正确送达、是否损坏我们无法得知,也无法保证。UDP 协议也是如此,它只管把数据包发送到网络,然后就不管了,如果数据丢失或损坏,发送端是无法知道的,当然也不会重发。

既然如此,TCP 应该是更加优质的传输协议吧?

如果只考虑可靠性,TCP 的确比 UDP 好。但 UDP 在结构上比 TCP 更加简洁,不会发送 ACK 的应答消息,也不会给数据包分配 Seq 序号,所以 UDP 的传输效率有时会比 TCP 高出很多,编程中实现 UDP 也比 TCP 简单。

UDP 的可靠性虽然比不上TCP,但也不会像想象中那么频繁地发生数据损毁,在更加重视传输效率而非可靠性的情况下,UDP 是一种很好的选择。比如视频通信或音频通信,就非常适合采用 UDP 协议;通信时数据必须高效传输才不会产生“卡顿”现象,用户体验才更加流畅,如果丢失几个数据包,视频画面可能会出现“雪花”,音频可能会夹带一些杂音,这些都是无妨的。

与 UDP 相比,TCP 的生命在于流控制,这保证了数据传输的正确性。

最后需要说明的是:TCP 的速度无法超越 UDP,但在收发某些类型的数据时有可能接近 UDP。例如,每次交换的数据量越大,TCP 的传输速率就越接近于 UDP。

基于UDP的服务器端和客户端

已剪辑自: http://c.biancheng.net/view/2359.html

前面的文章中我们给出了几个 TCP 的例子,对于 UDP 而言,只要能理解前面的内容,实现并非难事。

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

UDP 不像 TCP,无需在连接状态下交换数据,因此基于 UDP 的服务器端和客户端也无需经过连接过程。也就是说,不必调用 listen() 和 accept() 函数。UDP 中只有创建套接字的过程和数据交换的过程。

UDP服务器端和客户端均只需1个套接字

TCP 中,套接字是一对一的关系。如要向 10 个客户端提供服务,那么除了负责监听的套接字外,还需要创建 10 套接字。但在 UDP 中,不管是服务器端还是客户端都只需要 1 个套接字。之前解释 UDP 原理的时候举了邮寄包裹的例子,负责邮寄包裹的快递公司可以比喻为 UDP 套接字,只要有 1 个快递公司,就可以通过它向任意地址邮寄包裹。同样,只需 1 个 UDP 套接字就可以向任意主机传送数据。

基于UDP的接收和发送函数

创建好 TCP 套接字后,传输数据时无需再添加地址信息,因为 TCP 套接字将保持与对方套接字的连接。换言之,TCP 套接字知道目标地址信息。但 UDP 套接字不会保持连接状态,每次传输数据都要添加目标地址信息,这相当于在邮寄包裹前填写收件人地址。

发送数据使用 sendto() 函数:

ssize_t sendto(int sock, void *buf, size_t nbytes, int flags, struct sockaddr *to, socklen_t addrlen);  //Linux
int sendto(SOCKET sock, const char *buf, int nbytes, int flags, const struct sockadr *to, int addrlen);  //Windows

Linux 和 Windows 下的 sendto() 函数类似,下面是详细参数说明:

  • sock:用于传输 UDP 数据的套接字;
  • buf:保存待传输数据的缓冲区地址;
  • nbytes:带传输数据的长度(以字节计);
  • flags:可选项参数,若没有可传递 0;
  • to:存有目标地址信息的 sockaddr 结构体变量的地址;
  • addrlen:传递给参数 to 的地址值结构体变量的长度。

UDP 发送函数 sendto() 与TCP发送函数 write()/send() 的最大区别在于,sendto() 函数需要向他传递目标地址信息。

接收数据使用 recvfrom() 函数:

ssize_t recvfrom(int sock, void *buf, size_t nbytes, int flags, struct sockadr *from, socklen_t *addrlen);  //Linux
int recvfrom(SOCKET sock, char *buf, int nbytes, int flags, const struct sockaddr *from, int *addrlen);  //Windows

由于 UDP 数据的发送端不定,所以 recvfrom() 函数定义为可接收发送端信息的形式,具体参数如下:

  • sock:用于接收 UDP 数据的套接字;
  • buf:保存接收数据的缓冲区地址;
  • nbytes:可接收的最大字节数(不能超过 buf 缓冲区的大小);
  • flags:可选项参数,若没有可传递 0;
  • from:存有发送端地址信息的 sockaddr 结构体变量的地址;
  • addrlen:保存参数 from 的结构体变量长度的变量地址值。

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

下面结合之前的内容实现回声客户端。需要注意的是,UDP 不同于 TCP,不存在请求连接和受理过程,因此在某种意义上无法明确区分服务器端和客户端,只是因为其提供服务而称为服务器端,希望各位读者不要误解。

下面给出 Windows 下的代码,Linux 与此类似,不再赘述。

服务器端 server.cpp:

#include <stdio.h>
#include <winsock2.h>
#pragma comment (lib, "ws2_32.lib")  //加载 ws2_32.dll
#define BUF_SIZE 100
int main(){
    WSADATA wsaData;
    WSAStartup( MAKEWORD(2, 2), &wsaData);
    //创建套接字
    SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
    //绑定套接字
    struct sockaddr_in servAddr;
    memset(&servAddr, 0, sizeof(servAddr));  //每个字节都用0填充
    servAddr.sin_family = PF_INET;  //使用IPv4地址
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY); //自动获取IP地址
    servAddr.sin_port = htons(1234);  //端口
    bind(sock, (SOCKADDR*)&servAddr, sizeof(SOCKADDR));
    //接收客户端请求
    SOCKADDR clntAddr;  //客户端地址信息
    int nSize = sizeof(SOCKADDR);
    char buffer[BUF_SIZE];  //缓冲区
    while(1){
        int strLen = recvfrom(sock, buffer, BUF_SIZE, 0, &clntAddr, &nSize);
        sendto(sock, buffer, strLen, 0, &clntAddr, nSize);
    }
    closesocket(sock);
    WSACleanup();
    return 0;
}

代码说明:

  1. 第 12 行代码在创建套接字时,向 socket() 第二个参数传递 SOCK_DGRAM,以指明使用 UDP 协议。

  2. 第 18 行代码中使用htonl(INADDR_ANY)来自动获取 IP 地址。

利用常数 INADDR_ANY 自动获取 IP 地址有一个明显的好处,就是当软件安装到其他服务器或者服务器 IP 地址改变时,不用再更改源码重新编译,也不用在启动软件时手动输入。而且,如果一台计算机中已分配多个 IP 地址(例如路由器),那么只要端口号一致,就可以从不同的 IP 地址接收数据。所以,服务器中优先考虑使用 INADDR_ANY;而客户端中除非带有一部分服务器功能,否则不会采用。

客户端 client.cpp:

#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")  //加载 ws2_32.dll
#define BUF_SIZE 100
int main(){
    //初始化DLL
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
    //创建套接字
    SOCKET sock = socket(PF_INET, SOCK_DGRAM, 0);
    //服务器地址信息
    struct sockaddr_in servAddr;
    memset(&servAddr, 0, sizeof(servAddr));  //每个字节都用0填充
    servAddr.sin_family = PF_INET;
    servAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    servAddr.sin_port = htons(1234);
    //不断获取用户输入并发送给服务器,然后接受服务器数据
    struct sockaddr fromAddr;
    int addrLen = sizeof(fromAddr);
    while(1){
        char buffer[BUF_SIZE] = {0};
        printf("Input a string: ");
        gets(buffer);
        sendto(sock, buffer, strlen(buffer), 0, (struct sockaddr*)&servAddr, sizeof(servAddr));
        int strLen = recvfrom(sock, buffer, BUF_SIZE, 0, &fromAddr, &addrLen);
        buffer[strLen] = 0;
        printf("Message form server: %s\n", buffer);
    }
    closesocket(sock);
    WSACleanup();
    return 0;
}

先运行 server,再运行 client,client 输出结果为:

Input a string: C语言中文网
Message form server: C语言中文网
Input a string: c.biancheng.net Founded in 2012
Message form server: c.biancheng.net Founded in 2012
Input a string:

从代码中可以看出,server.cpp 中没有使用 listen() 函数,client.cpp 中也没有使用 connect() 函数,因为 UDP 不需要连接。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于UDP的服务器端和客户端 的相关文章

  • 从 iOS 应用程序上的 UDP 服务器接收数据无法在 Linux 服务器上工作,但可以在 macbook pro 上工作 [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 背景 我做
  • memcached 使用 Django 监听 UDP

    Question 我无法获得memcached正在听UDP 上班 get set delete 与姜戈 我只让 memcached 监听UDP 11211 正如我在上一个问题 https stackoverflow com question
  • Spark Scala UDP 在侦听端口上接收

    中提到的例子http spark apache org docs latest streaming programming guide html http spark apache org docs latest streaming pro
  • 为什么我的 UDP 广播失败?

    我正在尝试发送 UDP 广播 但wireshark 没有报告任何流量 这是执行发送的代码片段 void SendBroadcast String ip 255 255 255 255 int port 30718 String messag
  • 具有多个接口的 Python UDP 套接字

    我正在 Windows XP 机器上用 python2 7 编写脚本 本机使用不同的网卡连接到多个网络 我遇到了一个问题 我已将 UDP 套接字绑定到特定接口 我知道您可以通过仅提供网卡现有的 IP 地址来在 Windows 中完成此操作
  • 移动提供商无法进行 UDP 打洞

    实际上 我正在编写一个 Android 应用程序 该应用程序接收连接到 PC 的网络摄像头的图片 为了获得更多的 fps 我使用 udp 协议而不是 tcp 这个想法是 电脑将图片发送到手机的 IP 和端口 但电话提供商有不同的公共端口 所
  • 错误的 UDP 校验和没有效果:为什么?

    我正在尝试测试 UDP 程序 如果它接收到 UDP 校验和错误的数据 会发生什么情况 奇怪的是 它似乎没有任何效果 并且有效负载被成功接收 至少在 OS X 上是通过环回接口成功接收的 下面是一个示例 其中使用以下方式发送数据SOCK RA
  • NodeJS UDP 多播如何

    我正在尝试将 UDP 多播数据包发送到 230 185 192 108 以便每个订阅的人都会收到 有点卡住了 我相信它的广播正确 但似乎无法从任何客户端获取任何信息 Server var news Borussia Dortmund win
  • 为什么UDP服务器上的UDP客户端端口会改变

    我一直在关注一个简 单的 UDP 服务器 客户端教程 发现here http www binarytides com udp socket programming in winsock 我有一个关于客户端连接到服务器的端口的快速问题 仅从代
  • HTTP 是否使用 UDP?

    这可能是一个愚蠢的问题 HTTP 是否使用过用户数据报协议 例如 如果使用 HTTP 传输 MP3 或视频 它内部是否使用 UDP 进行传输 From RFC 2616 http www ietf org rfc rfc2616 txt 通
  • UDP sendto 上的 ECONNREFUSED 错误

    我在使用正在写入的应用程序时遇到一些无法解释的行为 使用 sendto 向多个端口发送 UDP 数据 所有端口均使用套接字 PF INET SOCK DGRAM 0 为了一组客户端读取进程的利益 这些 sendto 偶尔会不可预测地触发经济
  • 如何在QT中发送和接收UDP数据包

    我正在 QT 中编写一个小型应用程序 它通过本地网络发送广播 UDP 数据包 并等待来自网络上的一个或多个设备的 UDP 响应数据包 创建套接字并发送广播数据包 udpSocketSend new QUdpSocket this udpSo
  • 对等网络应用程序的网络发现

    我希望有两个类 一个服务器类和一个客户端类 服务器类应该接收每个新客户端的 IP 地址和端口号并将它们存储在列表中 它应该为每个客户端提供已连接客户端及其 IP 地址的列表 然后 客户端可以使用 TCP 连接相互通信 问题是客户端不知道服务
  • 为什么通过UdpClient发送会导致后续接收失败?

    我正在尝试创建一个 UDP 服务器 它可以向所有向其发送消息的客户端发送消息 真实情况要复杂一些 但最简单的方法是将其想象为一个聊天服务器 之前发送过消息的每个人都会收到其他客户端发送的所有消息 所有这一切都是通过UdpClient 在单独
  • 使用 STUN 打孔

    我目前正在尝试通过 Internet 发送 UDP 消息 并且必须为端点 A 和 B 都位于 NAT 后面 设置防火墙 为此 我想使用 STUN 服务器进行打孔 当 A 创建对 STUN 服务器的请求 例如 私有 85 1 1 12 600
  • 在 macOS 10.12 上绑定到套接字时出现 NSPOSIXErrorDomain

    我正在玩CocoaAsyncSocket https github com robbiehanson CocoaAsyncSocket在 Swift 中绑定到 UDP 套接字并通过本地网络接收消息 我正在初始化一个套接字 并尝试绑定到一个端
  • Python UDP广播不发送

    我正在尝试从 Python 程序到两个 LabView 程序进行 UDP 广播 我似乎无法发送广播 我不确定我的套接字初始化错误在哪里 广播似乎足够简单 据我所知 其他电脑没有收到任何数据 另外 我将来还需要这个程序来接收来自其他电脑的数据
  • 您可以bind()和connect() UDP连接的两端吗

    我正在编写一个点对点消息队列系统 它必须能够通过 UDP 运行 我可以任意选择一侧或另一侧作为 服务器 但这似乎不太正确 因为两端都从另一端发送和接收相同类型的数据 是否可以绑定 和连接 两端 以便它们只能彼此发送 接收 这似乎是一种非常对
  • 在 PowerShell 中通过 UDP 发送和接收数据

    我正在尝试编写一个脚本来使用 PowerShell 进行测试和应用 测试应包括通过 UDP 向远程服务器发送字符串 然后读取该服务器的响应并对结果执行某些操作 我需要的唯一帮助是脚本的中间两个步骤 发送字符串 然后 接收响应 在端口 UDP
  • 我应该害怕使用 UDP 进行客户端/服务器广播通话吗?

    我在过去的两天里阅读了每一篇StackOverflow问题和答案 以及googling当然 关于印地TCP and UDP协议 以便决定在我的用户应用程序和 Windows 服务之间的通信方法中应该使用哪一种 从我目前所看到的来看 UDP是

随机推荐

  • Matlab下多径衰落信道的仿真

    衰落信道参数包括多径扩展和多普勒扩展 时不变的多径扩展相当于一个延时抽头滤波器 xff0c 而多普勒扩展要注意多普勒功率谱密度 xff0c 通常使用Jakes功率谱 高斯 均匀功率谱 多径衰落信道由单径信道叠加而成 xff0c 而单径信道中
  • 硬件接口和软件接口

    文章目录 硬件接口IDESCSISATA光纤通道游戏设备RAID卡USBMD设备MP3视频音频 软件接口Java里的接口面向对象的接口 聊聊软件接口1 什么是接口2 诞生3 早期 xff08 1950 1970 xff09 4 快速发展 x
  • 有关C语言,定时器,周期任务的一些文章汇总

    测试C语言中打印一句 hello world需要耗费多少时间 C C 43 43 开源库 适合嵌入式的定时器调度器 C语言实现的多线程定时器 C语言操作时间函数 xff0c 实现定时执行某个任务小程序 C语言实现任务调度与定时器 Linux
  • SCADE简单了解

    随着新能源三电 智能驾驶等新技术的应用 xff0c 汽车中衍生出很多的安全零部件 xff0c 如BMS VCU MCU ADAS等 xff0c 相应的软件在汽车中的比重越来越大 xff0c 随之而来的安全性 可靠性要求也越来越高 ANSYS
  • 冯诺依曼体系结构与操作系统

    文章目录 详解冯诺依曼体系结构与操作系统前言1 简要背景介绍2 五大部件介绍3 细节解释4 举例理解冯诺依曼机中数据走向 二 全面认识操作系统1 操作系统的概念2 计算机系统 比对 银行系统3 深入认识 管理 xff1a 5 操作系统存在的
  • ADAS系统安全架构设计及安全等级的分解

    已剪辑自 https mp weixin qq com s PaFQDUR iOnEeueYQ82m w 笔者从事功能安全领域工作八年有余 xff0c 结合个人经验分享一下对系统安全架构设计的理解 xff0c 希望能够解决部分同行对于安全架
  • 汽车电子电气架构演进驱动主机厂多重变化

    已剪辑自 https mp weixin qq com s P56MaFODVc eZ4JEOVJvfA 汽车电子电气架构 xff08 EEA xff0c Electrical Electronic Architecture xff09 把
  • 编写可移植C/C++程序的要点

    以前做过两年C C 43 43 程序移植工作 xff0c 从Win32平台移植到Linux平台 大约有上百万行C C 43 43 代码 xff0c 历时一年多 在开发Win32版本时 xff0c 已经强调了程序的可植性 xff0c 无奈Wi
  • 智能座舱域控制器技术发展趋势分析

    已剪辑自 https mp weixin qq com s ajmpg7ThTUBerLvb2Bng9g 提到座舱域控制器用的主控SoC芯片 xff0c 大家第一个会想到应该就是高通的SA8155P 目前 xff0c 在主机厂新上市的中高端
  • 一个单片机驱动LCD编程思路

    文章目录 LCD种类概述TFT lcdCOG lcdOLED lcd 硬件场景预备知识面向对象驱动与设备分离 LCD到底是什么LCD驱动框架代码分析GUI和LCD层驱动IC层接口层总体流程 用法和好处字库声明 已剪辑自 https mp w
  • TinyFlashDB:一种超轻量的可纠错的通用单片机Flash存储方案

    文章目录 一 TinyFlashDB设计理念二 TinyFlashDB使用示例三 TinyFlashDB API介绍四 TinyFlashDB设计原理五 TinyFlashDB移植和配置六 移植到STM32单片机 已剪辑自 https mp
  • VR游戏交互开发的一些体验

    VR游戏交互开发的一些体验 本文主要写Unity开发手游过程中VR交互输入控制的一些浅薄的经验交互方面 xff0c 头控和视线按钮依然较为主流 xff0c 可以获得传感器数据来获得输入除了实体按钮输入之外还可以探索其他交互方式 xff0c
  • FTP、FTPS和SFTP的简介与区别

    FTP FTPS和SFTP的简介与区别 参考链接 xff1a https blog csdn net Mr Fan97 article details 119539189 FTP FTPS和SFTP简介 FTP FTP 即 文件传输协议 x
  • 基于功能安全的车载计算平台开发:硬件层面

    作为车载智能计算平台功能软件与系统软件的载体 xff0c 硬件的失效可能直接导致功能软件输出不可信任的结果 xff0c 从而违背安全目标 由于硬件故障在硬件生命周期中发生时间的随机性 xff0c 在通过改善流程降低系统性失效的同时 xff0
  • 基于功能安全的车载计算平台开发:系统层面

    相对于功能安全概念阶段 xff0c 系统阶段更专注于产品的详细设计 xff0c 涉及系统工程 安全工程和架构设计等不同技术领域 同时 xff0c 系统阶段也经常扮演着供应链上 下游功能安全的DIA交互阶段 xff0c 是功能安全中非常重要且
  • 神器必会!特别好使的编辑器Source Insight

    已剪辑自 https mp weixin qq com s nA9VJeMjC4gDpDSI8r 2FA Source Insight xff08 以下简称SI xff09 是世界上最好的编辑器 xff0c 说这句话不知道会不会出门被打呢
  • QT-GUI应用程序设计基础

    这里有一个容易搞混的点 xff0c 那就是widget h中的命名空间中的类Widget和在该文件中定义的类Widget不是同一个类 这其实也是很好理解的 xff0c 命名空间的作用其实就是将变量和类型的作用范围给控制起来 xff0c 这样
  • QT中怎么设置定时器/周期任务/定时触发任务

    Qt中定时器的使用有两种方法 xff0c 一种是使用QObject类提供的定时器 xff0c 还有一种就是使用QTimer类 其精确度一般依赖于操作系统和硬件 xff0c 但一般支持20ms 下面将分别介绍两种方法来使用定时器 QObjec
  • C语言Socket编程,实现两个程序间的通信

    文章目录 server和client通信流程图实现两个程序间的通信1 服务端server2 客户端client3 怎么运行呢 xff1f 4 重写代码 已剪辑自 https www cnblogs com fisherss p 120851
  • 基于UDP的服务器端和客户端

    文章目录 再谈UDP和TCP基于UDP的服务器端和客户端UDP中的服务器端和客户端没有连接UDP服务器端和客户端均只需1个套接字基于UDP的接收和发送函数基于UDP的回声服务器端 客户端 再谈UDP和TCP 已剪辑自 http c bian