Windows 环境下的 Socket 编程 4 - 基于 UDP 的服务器/客户端

2023-05-16

在 TCP 中,套接字之间应该是一对一的关系。若向 10 个客户端提供服务,则除了守门的服务器套接字外,还需要 10 个服务器端套接字。但在 UDP 中,不管是服务器端还是客户端都只需要 1 个套接字

基于 UDP 的数据 I/O 函数

UDP 套接字不会保持连接状态,因此每次传输数据都要添加目标地址信息

  1. sendto 函数
//发送数据函数,成功返回传输的字节数,失败时返回 -1
int sendto(SOCKET s,const char *buf,int len,int flags,const struct sockaddr *to,int tolen);
  • s:套接字
  • buf:指向待传输数据的缓冲区
  • len:待传输数据的长度
  • flags:可选参数,若没有则传递 0
  • to:指向包含目的地址信息的 sockaddr 结构体变量
  • tolen:变量 to 的长度
  1. recvfrom 函数
//接收数据函数,成功时返回接收的字节数,失败时返回 -1
int WSAAPI recvfrom(SOCKET s,char *buf,int len,int flags,struct sockaddr *from,int *fromlen);
  • s:套接字
  • buff:指向保存接收数据的缓冲区
  • len:可接收的最大字节数
  • flags:可选参数,若没有则传入 0
  • from:指向包含发送端地址信息的 sockaddr 结构体变量
  • fromlen:指向保存变量 from 长度的变量

什么时候调用 recvfrom ,当操作系统接收到 UDP 数据, 会自动通知(回调)应用程序吗?
如果 len 很小,对方又发送大数据包,如何知道接收缓冲区的数据大小,以方便多次读取?
如果 len 很大,recvfrom 函数会一直等待吗?

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

UDP 不同于 TCP,不存在请求连接和受理过程,因此在某种意义上无法明确区分服务器端和客户端。只是因其提供服务而称为服务器端。
服务器端实现:

#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>

void ErrorHandler(char *message);

#define BUF_SIZE 1024
int main(int argc, char *argv[])
{
    WSADATA wsaData;
    SOCKET hServSock, hClntSock;
    struct sockaddr_in servAddr, clntAddr;
    int szClntAddr;
    char message[BUF_SIZE];
    int strLen, i;
    if(argc != 2)
    {
        printf ("Usage: %s <port>\n", argv[0]);
        exit(1);
    }

    if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
        ErrorHandler("WSAStartup failed");

    hServSock = socket(PF_INET, SOCK_DGRAM, 0);
    if(hServSock == INVALID_SOCKET)
        ErrorHandler("socket error");
    
    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servAddr.sin_port = htons(atoi(argv[1]));

    if(bind(hServSock, (struct sockaddr *)&servAddr, sizeof(servAddr)) == SOCKET_ERROR)
        ErrorHandler("bind socket error");
    
    while(1)
    {
        strLen = recvfrom(hServSock, message, BUF_SIZE, 0, (struct sockaddr *)&clntAddr, &szClntAddr);
        sendto(hServSock, message, strLen, 0, (struct sockaddr *)&clntAddr, sizeof(clntAddr));
    }
    closesocket(hServSock);
    WSACleanup();
    return 0;
}

void ErrorHandler(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

客户端实现:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>

#define BUF_SIZE    1024
void ErrorHandler(char *message);

int main(int argc, char *argv[])
{
    WSADATA wsaData;
    SOCKET hClntSock;
    struct sockaddr_in servAddr,fromAddr;
    char message[BUF_SIZE];
    int strLen;
    int adr_sz;
    if(argc != 3)
    {
        printf ("Usage: %s <IP> <port>\n", argv[0]);
        exit(1);
    }

    if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
        ErrorHandler("WSAStartup failed");

    hClntSock = socket(PF_INET, SOCK_DGRAM, 0);
    if(hClntSock == INVALID_SOCKET)
        ErrorHandler("socket error");
    
    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = inet_addr(argv[1]);
    servAddr.sin_port = htons(atoi(argv[2]));


    while(1)
    {
        fputs("Input message(Q to quit): ",stdout);
        fgets(message, BUF_SIZE, stdin);

        if(!strcmp(message, "q\n") ||!strcmp(message, "Q\n"))
            break;

        sendto(hClntSock, message, strlen(message), 0, (struct sockaddr *)&servAddr, sizeof(servAddr));
        strLen = recvfrom(hClntSock, message, BUF_SIZE, 0, (struct sockaddr *)&fromAddr, &adr_sz);
        message[strLen] = 0;
        printf("Message from server: %s", message);
    }
    
    closesocket(hClntSock);
    WSACleanup();
    return 0;
}

void ErrorHandler(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

UDP 套接字存在数据边界

TCP 数据传输不存在边界,这表示数据传输过程中调用 I/O 函数的次数不具有任何意义。但是,UDP 是具有数据边界的协议,传输中调用 I/O 函数的次数非常重要。调用 3 次 sendto 发送的函数要调用 3 次 recvfrom 函数才能接收完。

已连接的 UDP 套接字

使用 sendto 函数,每次都要传入目标地址信息,这在某些场合会低效且繁琐,已连接的 UDP 套接字可以解决这个问题

  1. connect 函数:创建已连接的 UDP 套接字
/*成功返回 0 ,失败返回 SOCKET_ERROR */
int connect(SOCKET s, const struct sockaddr *name, int namelen);

这个函数参数与 TCP 相同,但是结果不同,TCP 调用这个函数会进行 3 次握手,UDP 调用这个函数只是注册目标 IP 和端口信息。
一旦调用 connect 函数后,就不必使用 sendtorecvfrom 函数发送和接收数据,取而代之的是和 TCP 相同的 API 函数:sendrecv

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

Windows 环境下的 Socket 编程 4 - 基于 UDP 的服务器/客户端 的相关文章

  • python split使用多个分隔符分割字符串

    1 python内建的split 函数只能使用单个分隔符 text 61 39 你好 xff01 吃早饭了吗 xff1f 再见 39 text split 39 xff01 39 Out 64 39 你好 39 39 吃早饭了吗 xff1f
  • python 获取指定文件夹下所有文件名

    使用os模块可以获取指定文件夹下所有文件名 xff0c 有两个方法os walk 和os listdir 1 os walk可以用于遍历指定文件下所有的子目录 非目录子文件 import os filePath 61 39 C myLear
  • pandas之values和value_count()用法:结合JData ”用户购买时间预测“数据分析实例(一)

    表1 xff1a SKU基本信息表 xff08 jdata sku basic info xff09 1 读取数据 xff0c 并获取部分特征的最大值 xff0c 最小值 xff0c 均值和中位数 2 df info 给出DataFrame
  • 自然语言处理学习3:中文分句re.split(),jieba分词和词频统计FreqDist

    1 使用re split 分句 xff0c re split delimiter text import jieba import re 输入一个段落 xff0c 分成句子 xff0c 可使用split函数来实现 paragraph 61
  • React 实现一个计数器

    新建组件 views components count js xff1a span class token keyword import span span class token punctuation span Component sp
  • Python编程学习5:python id()函数和内存分配理解

    1 id 函数可返回对象的内存地址 python中会为每个对象分配内存 xff0c 哪怕他们的值完全相等 id object 函数是返回对象object在其生命周期内位于内存中的地址 xff0c id函数的参数类型是一个对象 如下例子 xf
  • 鬼吹灯文本挖掘3:关键词提取extract_tags和使用sklearn TfidfTransformer 计算TF-IDF矩阵

    鬼吹灯文本挖掘1 xff1a jieba分词和CountVectorizer向量化 鬼吹灯文本挖掘2 xff1a wordcloud 词云展示 鬼吹灯文本挖掘3 xff1a 关键词提取和使用sklearn 计算TF IDF矩阵 鬼吹灯文本挖
  • pandas 之 to_csv 保存数据出现中文乱码问题及解决办法

    1 使用scrapy框架爬取了一些汽车评价保存在csv文件中 xff0c 但是直接打开时乱码了 2 使用pandas读取再使用to csv 方法重新保存 import pandas as pd file name 61 39 G myLea
  • 004_sklearn pipeline 和Gridsearch的使用

    1 sklearn pipeline的使用 xff08 1 xff09 简介 当我们对训练集应用各种预处理操作时 xff08 特征标准化 主成分分析等等 xff09 xff0c 我们都需要对测试集重复利用这些参数 pipeline 实现了对
  • Eclipse 查看源代码Source not found

    1 Eclipse 快捷键 ctrl 43 鼠标左键可以查看Java 类 函数的源代码 2 有时Eclipe配置不好时 xff0c 会出现source not found的问题 解决方法如下 xff1a xff08 1 打开window种的
  • realsense内参、外参获取

    启动相机节点 roslaunch realsense2 camera rs camera launch 查看相机参数信息 rostopic echo camera depth camera info 内参矩阵格式 fx 焦距xfy 焦距yx
  • ROS控制crazyflie无人机(一)

    ROS控制crazyflie无人机 参考资料测试环境一 设置用户权限二 安装Crazyflie程序库和客户端三 安装crazyflie ros程序包四 遥控器控制crazyflie无人机 本篇博客记录了测试使用ros控制crazyflie无
  • echarts 黑色样式

    lt THIS EXAMPLE WAS DOWNLOADED FROM https echarts apache org examples zh editor html c 61 dataset simple1 gt lt DOCTYPE
  • 磁盘分区

    磁盘 xff1a 可以被分区成多个分区槽 xff08 partition xff09 以Windows来看 xff0c 磁盘可以被分区为 C xff1a xff0c D xff1a xff0c E xff1a 槽 C D E就是分区槽 而L
  • 【STM32】IAP下载程序分析

    IAP下载程序分析 IAP基本原理STM32启动流程程序跳转代码实现总结 IAP基本原理 要实现STM32的IAP xff08 在应用编程 xff09 xff0c 需要分别建立bootloader和app工程 这里的bootloader程序
  • vue el-date-picker 设置可选近30天且时间范围为7天

    对 el date picker 限制 xff1a 默认选择时间范围为最近一天 xff1b 设置快捷选项 xff1a 最近1天 最近3天 最近7天等 xff1b 限制只能选择今天以及今天以前30天 xff1b 选择一个时间之后 xff0c
  • MySQL索引分析

    1 索引是什么 xff1f 索引是一种能提高数据库查询效率的数据结构 它可以比作一本字典的目录 xff0c 可以帮你快速找到对应的记录 索引一般存储在磁盘的文件中 xff0c 它是占用物理空间的 正所谓水能载舟 xff0c 也能覆舟 适当的
  • 任务是如何调度(切换)的?

    学习任务的切换有助于自己理解操作系统的运行过程 并且任务的调度 xff08 切换 xff09 也是操作系统中的重要的部分 任务的切换中关键是任务控制块的控制 xff0c 将现在以及将来要运行的任务向堆栈中的存储与恢复 因为 C OS II总
  • 机器学习算法五:随机森林(Random Forest)

    集成学习 xff1a 通过构建并结合多个学习器来完成学习任务 xff1b 集成学习中主要包括boosting算法 和bagging算法 xff1b boosting算法 xff1a xff08 线性集成 xff09 关注于降低偏差 xff1
  • 怎样利用VNC远程连接LINUX桌面

    关于显示等问题都有 xff0c 比较详细 http blog csdn net zhouyunjie archive 2008 11 27 3396824 aspx 先要修改 vnc xstartup文件 bin sh Uncomment

随机推荐

  • VNC多用户

    1 为vnc建立用户 newuser 2 拷贝 root vnc 里的xstartup文件到用户目录 home newuser 3 修改xstartup文件 xff0c 在最后增加 xff1a gnome session amp 4 以ne
  • 【环境配置】初试使用mitmproxy搭建网络代理

    初试使用mitmproxy搭建网络代理 1 参考文章 老版本的很多功能已经不能用了 xff0c 用新的版本研究了一下 参考文章 https mitmproxy org http www freebuf com sectool 76361 h
  • 关于Keil 的快速注释功能,并为其添加快捷键

    原地址 xff1a http blog sina com cn s blog 6859cadf0101i3p4 html Keil版本uVision 4 03 1 在Keil gt Edit gt Advanced中有两项 Comment
  • 【OpenCV】ArUco Marker

    1 创建 span class token keyword import span cv2 span class token keyword as span cv span class token keyword import span n
  • 非常实用,华为、新华三、锐捷交换机的配置命令分享

    干弱电这一行难免会接触到交换机 xff0c 华为 新华三锐捷交换机又是最常见的交换机 xff0c 关于他们的命令配置很容易弄混 xff0c 而且在实际项目配置中也很容易出错 xff0c 因此 xff0c 本期我们将来介绍这三家交换机的基础配
  • 打飞机小游戏

    设计目标 xff1a 高质量的代码要有这些优点 复用性好 扩展性好 维护性好 可移植性好 健壮性好 效率好 可读性好 所以设计代码的时候不要只想到功能的实现 xff0c 还要考虑功能的扩展及代码复用等 设计规则 xff1a 需求分析抽取共性
  • windows 安装 Navicat Premiun

    Navicat Premiun 中文网站 Navicat Premiun 官网下载 简介 Navicat Premium 是一套数据库管理工具 xff0c 结合其它Navicat 成员 xff0c 支持单一程序同时连接到 MySQL Mar
  • 论文排版中MathType的使用(论文投稿必备)

    使用mathtype往论文中插入公式时 xff0c 若需要编号 xff0c 则点击 右编号 xff08 若只需插入文本行内 xff0c 则点 内联 xff09 由于论文是分栏格式 xff0c 单行公式太长导致编号串行 xff0c 因此需要将
  • python语言中变量的共享引用及原处修改

    代码段一 xff1a 代码段1 gt gt gt a 61 6 gt gt gt b 61 a gt gt gt a b 输出 xff1a 6 6 上述代码段一中 xff0c 第一行我们创建了对象6 xff0c 并将变量a 与之相关联 xf
  • 通用环形缓冲区 LwRB 使用指南

    什么是 LwRB xff1f LwRB 是一个开源 通用环形缓冲区库 xff0c 为嵌入式系统进行了优化 源码点击这里 Github LwRB 特性 使用 ANSI C99 编写FIFO xff08 先进先出 xff09 无动态内存分配 x
  • Windows 环境下的 Socket 编程 3 - 基于 TCP 的服务器/客户端

    基于 TCP 的服务器端 客户端 绝大多数 TCP 服务器端都按照如下顺序调用 xff1a 在 Windows 环境下 xff0c 代码表示为 xff1a WSADATA wsaData span class token punctuati
  • 随想006:帮忙的时机

    我一直不理解发生在我身边的一个现象 从我第一次发现到现在已经几年了 xff0c 在一个又一个人身上 xff0c 不断地出现 在编程界 xff0c 重复 可能是软件中一切邪恶的根源 xff0c 我为此吃过苦头 让我记忆尤深的是 xff0c 当
  • 仿真软件 LTspice XVII 操作方法

    原理图编辑 与其它软件不同 xff0c LTspice XVII 软件先选择动作 xff0c 然后选择对象 比如要移动一个元件时 xff0c 首先选择 移动 xff08 move xff09 命令 xff0c 然后单击一个元件或框住一系列元
  • LwIP IP 层常用函数和宏

    1 将 4 字节数据组成 IP 地址 头文件 xff1a ip addr h span class token function IP ADDR4 span span class token punctuation span ipaddr
  • 测试驱动的嵌入式开发 001:VSCode + CMake + CppUTest 环境搭建

    本文是对 测试驱动的嵌入式 C 语言开发 第二章的实践 对资源受限的嵌入式项目如何进行测试驱动开发的所有疑问 xff0c 都因为本书第二章最开始的一句话而消解 xff0c 当我读到这句话时 xff0c 脑袋里有闪电掠过 这句话是 xff1a
  • 测试驱动的嵌入式开发 002:VSCode + CMake + Unity 环境搭建

    本文是对 测试驱动的嵌入式 C 语言开发 第二章的实践 搭建 VSCode 这部分参考博文 基于Windows 的 VS Code C C 43 43 编译环境搭建 安装 CMake 安装 CMake xff0c 在官网下载最新安装包 安装
  • 原理图与 PCB 绘制备忘

    原理图绘制 导出 BOM 点击菜单 Reports Bill of Materials xff0c 在弹出的生成 BOM 界面中 xff0c 点击 OK 按钮导出 BOM 批量修改器件标识 xff08 比如型号 xff0c 阻值 xff09
  • Windows 10 安装 MySQL

    确认是否已安装 MySQL xff08 1 xff09 按 win 43 r 快捷键打开运行 xff1b xff08 2 xff09 输入 services msc xff1b xff08 3 xff09 点击 确定 xff0c 在打开的服
  • lwIP 细节之四:ARP 相关知识

    ARP 表项的最大存活时间与宏 ARP MAXAGE 相关 xff0c 默认为 240 x 5000ms 61 20 分钟 当 ARP 表项还有最后一分钟 xff08 由宏 ARP AGE REREQUEST USED 控制 xff09 存
  • Windows 环境下的 Socket 编程 4 - 基于 UDP 的服务器/客户端

    在 TCP 中 xff0c 套接字之间应该是一对一的关系 若向 10 个客户端提供服务 xff0c 则除了守门的服务器套接字外 xff0c 还需要 10 个服务器端套接字 但在 UDP 中 xff0c 不管是服务器端还是客户端都只需要 1