UDP通信入门篇

2023-05-16

UDP通信属于网络通信中的一种方式,需要用套接字来进行通信。
初接触UDP通信时,不知道需要链接静态库#pragma comment(lib,“ws2_32.lib”),导致自己在前期浪费了很多时间去排查问题。除了静态库之外,用到的头文件还有<winsock.h>。

通信流程如下:
接收端(服务器):
1.创建套接字
2.将套接字绑定到一个本地地址和端口上(bind)
3.等待接受数据(recvform)
4.关闭套接字

发送端(客户端):
1.创建套接字
2.向服务器发送数据(sendo)
3.关闭套接字

各个函数及类型的说明如下:

sockaddr_in addr;//创建一个结构体,用来定义套接字的地址形式,有四个参数,分别代表协议类型、端口号、IP地址,第四个参数不用管,好像是没意义,原型如下:
struct sockaddr_in {
        short   sin_family;			//参数选择AF_INET,代表IPV4,UDP/TCP
        u_short sin_port;			//确定端口,一般用htons(int a)进行转化
        struct  in_addr sin_addr;	//确定IP
        char    sin_zero[8];
};
 htons(int a);						//将主机字节顺序转换为网络字节顺序;
 									//htons 把unsigned short类型从主机序转换到网络序;
 									//htonl 把unsigned long类型从主机序转换到网络序
/*addr.sin_addr.s_addr是ip地址,作为服务器,要绑定【bind】到本地的IP地址上进行监听【listen】,
但是机器上可能有多块网卡,也就有多个IP地址,这时候要选择绑定在哪个IP上面,如果指定为INADDR_ANY,
那么系统将绑定默认的网卡【即IP地址】*/
WSAStartup(MAKEWORD(SOCK_VER, 0), &wd);
函数原型: WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData)
WSAStartup,即WSA(Windows SocKNDs Asynchronous,Windows异步套接字)的启动命令。
为了在应用程序当中调用任何一个Winsock API函数,首先第一件事情就是必须通过WSAStartup函数完成对Winsock服务的初始化,因此需要调用WSAStartup函数。
使用Socket的程序在使用Socket之前必须调用WSAStartup函数。该函数的第一个参数指明程序请求使用的Socket版本,其中高位字节指明副版本、低位字节指明主版本;
操作系统利用第二个参数返回请求的Socket的版本信息。当一个应用程序调用WSAStartup函数时,操作系统根据请求的Socket版本来搜索相应的Socket库,然后绑定找到的Socket库到该应用程序中,以后应用程序就可以调用所请求的Socket库中的其它Socket函数了。该函数执行成功后返回0。
MAKEWORD(a, b)作用是把a和b拼接成为一个无符号的16位整形数,返回的结果是:(a|b<<8)
LOBYTE(a)是取得16进制数最低(最右边)那个字节的内容;HIBYTE(a)是取得16进制数最高(最左边)那个字节的内容。
socket(AF_INET, SOCK_DGRAM, 0);
函数原型:socket(int af, int type, int protocol)
socket函数接受3个参数.
第一个参数(af)指定地址族, 对于TCP / IP协议的套接字, 它只能是AF_INET(也可以写成PF_INET); 
第二个参数(type)指定Socket类型, 对于1.1版本的Socket, 他只支持两种类型的套接字, SOCKE_STREAM指定产生流式套接字, SOCK_DGRAM产生数据报套接字; 
第三个参数(protocol)是与特定的地址家族相关的协议, 如果指定为0, 那么系统就会根据地址格式和套接类别, 自动选择一个合适的协议.这是推荐使用的一种选择协议的方法.
如果socket函数调用成功, 他就会返回一个新的socket数据类型的套接字描述符; 如果调用失败, 这个函数返回一个INVALID_SOCKET值, 错误信息可以通过WSAGetLastError函数返回.
bind(sockUDP, (sockaddr*)&addr, sizeof(struct sockaddr_in));
函数原型:bind(SOCKET s, const sockaddr *addr, int namelen)
把套接字和端口绑定,成功返回0,服务器进行绑定操作,将一本地地址与一套接口捆绑。
当用socket()创建套接口后,它便存在于一个名字空间(地址族)中,但并未赋名。bind()函数通过给一个未命名套接口分配一个本地名字来为套接口建立本地捆绑(主机地址/端口号)。
bind函数一般用在接收端,发送端无需配置
sendto(sockUDP, (char*)"wertqw", 3, 0, (sockaddr*)&send2Addr, sizeof(send2Addr));
函数原型:sendto(SOCKET s, const char *buf, int len, int flags, const sockaddr *to, int tolen)

recvfrom(sockUDP, (char*)buf, 1024, 0, (sockaddr*)&saServer, &nFromLen);
函数原型:recvfrom(SOCKET s, char *buf, int len, int flags, sockaddr *from, int *fromlen)
sendto(),是把UDP数据报发给指定地址;recvfrom()是从指定地址接收UDP数据报。
参数说明:
s:            socket描述符。
*buf:         UDP数据报缓存地址。
len:          UDP数据报长度。
flags:        该参数一般为0。
*to:          sendto()函数参数,struct sockaddr_in类型,指明UDP数据发往哪里报。
tolen:        对方地址长度,一般为:sizeof(struct sockaddr_in)。
*from:        recvfrom()函数参数,struct sockaddr_in类型,指明从哪里接收UDP数据报。
*fromlen       对方地址长度,一般为:&sizeof(struct sockaddr_in)。

函数返回值:
对于sendto()函数,成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno 中。
对于recvfrom()函数,成功则返回接收到的字符数,失败则返回-1,错误原因存于errno中。
注:对于接收和发送,个人感觉是:我可以随便接收数据,但你只能向我发送
closesocket(sockUDP);//关闭socket句柄
WSACleanup();//应用程序在完成对请求的Socket库的使用后,要调用WSACleanup函数来解除与Socket库的绑定并且释放Socket库所占用的系统资源

服务器代码:

void udpServer()
{
	WSADATA wsaData;
	int err = WSAStartup(MAKEWORD(1, 1), &wsaData);
	cout << "UDP server is operating!" << endl;

	//创建套接字
	SOCKET sockServe = socket(AF_INET, SOCK_DGRAM, 0);	

	//创建服务器的端口和IP地址
	sockaddr_in addrServe={0};
	addrServe.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	addrServe.sin_family = AF_INET;
	addrServe.sin_port = htons(6000);

	//绑定套接字和端口,服务端绑定操作
	bind(sockServe, (SOCKADDR*)&addrServe, sizeof(SOCKADDR));

	//创建客户端的端口和IP地址变量,用于存储
	sockaddr_in addrClient={0};  

	int len = sizeof(SOCKADDR);

	char recvBuf[100];
	memset(recvBuf, 0, 100);
	//发送数组暂时屏蔽
	//char sendBuf[100]; 
	//memset(sendBuf, 0, 100);
	//strcpy_s(sendBuf, "Hello,UDP Client!") ;

	while (1)
	{
		//sockServe从addrClient接收数据
		int numBytes=recvfrom(sockServe, recvBuf, 100, 0, (SOCKADDR*)&addrClient, &len);
		if(numBytes>0)
			cout << recvBuf << endl;
	}

	closesocket(sockServe);
	WSACleanup();
}

客户端代码:

void udpClient()
{
	WSADATA wsaData;
	int err = WSAStartup(MAKEWORD(1, 1), &wsaData);
	cout<<"UDP client is operating!"<<endl;
	
	//创建套接字
	SOCKET sockClient = socket(AF_INET, SOCK_DGRAM, 0);

	//创建服务器的端口和IP地址
	sockaddr_in  addrServer={0};
	addrServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//输入要通信的地址
	addrServer.sin_family = AF_INET;
	addrServer.sin_port = htons(6000);

	int len = sizeof(SOCKADDR);

	char sendBuf[100]; 
	memset(sendBuf, 0, 100);
	strcpy_s(sendBuf, "Hello,UDP Server!") ;

	//sockClient向addrServer发送数据
	sendto(sockClient, sendBuf, strlen(sendBuf), 0, (SOCKADDR*)&addrServer, len);

	closesocket(sockClient);
	WSACleanup();
}

第二天的经验:
1.对于既需要接收数据又要发送数据的函数,最好把发送放在接收之后,目的是为了目标地址,通过recvfrom函数可以得到所接收数据的来源地址及端口,并存储到sockaddr *from中,这时,在发送数据(sendto函数)时,只要把目的地址用sockaddr *from表示就可以了。
2.recvfrom函数是阻塞接受的,当一直接收不到数据时,程序就会卡在recvfrom函数处,除非发送一个数据让其接收。解决其阻塞接收的方法:在recvfrom函数前添加下面的代码:

ULONG nVal = 1;
ioctlsocket(clientSock, FIONBIO, &nVal);
//暂未查看代码的作用

3.UDP是一种不可靠的数据传输方式,服务器端/客户端并不需要在连接状态下交换数据,不存在请求连接和受理连接的过程,因此某种意义上并没有明确的服务器端和客户端之分,它的通信只有创建套接字和数据交换的过程,无论服务器端还是客户端都只需要一个套接字即可,且可以实现一对多的通信关系。
4.远程地址指的是对端,本地地址指的是本端,本段端口与对端端口进行数据交换,在不同的函数中,注意区分好本段和对端分别对应的是什么。
5.一般来说,PC有两个IP地址可以用来进行测试,一个是127.0.0.1,另一个是IPv4地址

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

UDP通信入门篇 的相关文章

  • UDP 数据报中发送的消息未经过净化?

    我的代码如下 一切都按照我想要的方式进行 但是当我的消息收到时 它们的末尾有很多框 有点像这样 消息 你好 如何才能让接收和打印的内容仅为 Message hello 我非常感谢任何帮助 import java io import java
  • GCDAsyncUDPSocket源地址返回null

    谷歌代码问题镜像 https groups google com forum topic cocoaasyncsocket grhjZSMLr3U https groups google com forum topic cocoaasync
  • memcached 使用 Django 监听 UDP

    Question 我无法获得memcached正在听UDP 上班 get set delete 与姜戈 我只让 memcached 监听UDP 11211 正如我在上一个问题 https stackoverflow com question
  • UDP 服务器套接字缓冲区溢出

    我正在 Linux 上编写 C 应用程序 我的应用程序有一个 UDP 服务器 它在某些事件上向客户端发送数据 UDP 服务器还接收来自客户端的一些反馈 确认 为了实现这个应用程序 我使用了一个 UDP 套接字 例如int fdSocket
  • 简单的udp代理解决方案

    我正在寻找可以代理我的 udp 数据包的解决方案 我有一个客户端向服务器发送 udp 数据包 它们之间的连接非常糟糕 导致大量数据包丢失 一种解决方案是使用一个新的代理服务器 它将所有数据包从客户端重定向到目标服务器 新的代理服务器与这两个
  • 我应该使用哪个高级 API 来管理 iOS 上的 UDP 套接字? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 在章节 使用套接字和流 https developer apple com library mac d
  • 如何在多个程序中接收相同的udp流?

    我有一个封闭的第三方系统 它发送单播 UDP 流 MPEG TS 我想在同一台计算机上的两个不同程序中访问该流 我无法更改源上的任何内容 甚至无法更改 IP 或端口 除了编写自己的小程序来捕获流然后创建新流并重新发送这两个流之外 还有其他选
  • 为什么UDP服务器上的UDP客户端端口会改变

    我一直在关注一个简 单的 UDP 服务器 客户端教程 发现here http www binarytides com udp socket programming in winsock 我有一个关于客户端连接到服务器的端口的快速问题 仅从代
  • DatagramChannel.close() 在 Windows 上保持端口打开

    我正在实施一个发现流程 打开 UDP 套接字以侦听给定端口上的广播响应 发送一些请求 并期待稍后的响应 在给定时间段后关闭 UDP 套接字 第一次通话有效 但其他调用会出现绑定错误 地址已被使用 绑定 我运行的是Windows 7 我做了一
  • 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 偶尔会不可预测地触发经济
  • iOS 14 在进行本地网络广播时给出“操作系统错误:错误的文件描述符,errno = 9”

    做一点Jeopardy 风格问答 https stackoverflow blog 2011 07 01 its ok to ask and answer your own questions here 我正在 Flutter 中开发一个应
  • 接收UDP数据包

    假设我的程序通过网络 UDP 发送 1000 字节 它是否保证接收方将 一批 接收 1000 个字节 或者他可能需要执行多次 读取 直到收到完整的消息 如果后者为真 我如何确保同一消息的数据包顺序不会 混淆 按顺序 或者协议可能保证这一点
  • 您可以bind()和connect() UDP连接的两端吗

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

    我目前正在为 F1 方向盘开发自己的显示器 F1 2019 由codemasters提供 通过UDP发送数据 该数据存储在字节数组中 我在解码返回的数组时遇到一些问题 问题是我得到了很多信息 但我不知道如何处理它们 我将向您介绍我所尝试过的
  • 我应该害怕使用 UDP 进行客户端/服务器广播通话吗?

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

    我正在准备考试 发现了这个问题 典型的 UDP 服务器可以使用单个套接字来实现 解释一下为什么 对于 TCP 驱动的服务器 我发现创建了两个套接字 一个用于所有客户端访问服务器 另一个用于每个客户端的特定 套接字 用于服务器和客户端之间的进
  • 如何使用 Nmap 检索 TCP 和 UDP 端口? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我需要在使用 Nmap 的同一扫描中以尽可能最快的方式检索 TCP 和 UDP 端口 我会尽力解释得更好 如果我使用最常用的命令 nmap 192 1
  • 从不同进程通过套接字 (UDP) 回复客户端

    我有一个服务器而不是 命令处理程序 进程 它通过 UDP 接收消息 并通过其发布的 API 无论该进程采用何种 IPC 机制 与该进程进行通信 从而将要做的工作委托给不同的进程 我们的系统有多个协作进程 然后 该 API 调用的结果会从命令
  • 使用多个 NIC 广播 UDP 数据包

    我正在 Linux 中为相机控制器构建嵌入式系统 非实时 我在让网络做我想做的事情时遇到问题 该系统有 3 个 NIC 1 个 100base T 和 2 个千兆端口 我将较慢的连接到相机 这就是它支持的全部 而较快的连接是与其他机器的点对

随机推荐

  • 2.7.C++中static关键字的5种基本用法

    static关键字 static关键字主要应用于以下几种情况 xff1a 情况1 xff1a static静态函数 定义静态函数 xff1a 在函数返回类型前加上static关键字 xff0c 函数即被定义为静态函数 静态函数只能在本源文件
  • 进程调度算法

    进程调度 在多道程序系统中 xff0c 进程数量往往多于处理机的个数 xff0c 因此进程竞争使用处理机的情况在所难免 处理机调度是对处理机进行分配 xff0c 即从就绪队列中按照一定的算法选择一个进程并将处理机分配给它运行 xff0c 以
  • git clone 出现fatal: unable to access ‘https://github 类错误解决方法

    git clone 遇到问题 xff1a fatal unable to access https github comxxxxxxxxxxx Failed to connect to xxxxxxxxxxxxx 问题 将命令行里的http
  • 进程通信的方式

    进程通信 1 进程通信的概念 进程是一个独立的资源分配单元 xff0c 不同进程 xff08 主要是指不同的用户进程 xff09 之间的资源是独立的 xff0c 没有关联的 xff0c 不能在一个进程中直接访问另一个进程的资源 但是 xff
  • 网络通信的过程

    网络通信的过程 封装 上层协议时如何使用下层协议提供的服务的呢 xff1f 其实这是通过封装实现的 应用程序是在发送到物理网络上之前 xff0c 将沿着协议栈从上往下依次传递 每层协议都将在上层数据的基础上加上自己的头部信息 xff08 有
  • TCP三次握手、四次挥手

    TCP通信流程 TCP和UDP TCP和UDP区别如下 xff1a UDP xff1a 用户数据报文协议 xff0c 面向无连接 xff0c 可以单播 xff0c 多播 xff0c 广播 xff0c 面向数据报 xff0c 不可靠 TCP
  • Qt的多线程编程

    Qt线程 基本概念 并发 当有多个线程在操作时 xff0c 如果系统只有一个CPU xff0c 则它根本不可能真正同时进行一个以上的线程 xff0c 它只能把CPU运行时间划分成若干个时间段 xff0c 再将时间段分配给各个线程执行 xff
  • CMake编译C++文件

    这篇文章介绍如何使用cmake工具编译一个最简单的helloworld cpp文件 首先创建一个空的文件夹 mkdir cmake test 在该文件夹下 xff0c 我们新建一个helloworld cpp文件 span class to
  • 智能小车建图导航-在rviz中导航(运行)

    笔记来源 xff1a 机器人开发与实践 xff08 古月 xff09 或者直接运行这个脚本文件 xff1a xff08 如果你没有在 bracsh文件中加入source xff0c 建议加入或者在脚本文件的上面中添加source xff0c
  • 004-S500无人机-相关的器件参数以及计算

    这篇博客主要是记录S500无人机的相关器件的参数 xff0c 参数的来源来源于holybro官网 xff1a https shop holybro com 我这里进行参数的归纳以及计算 一 电机 xff08 2216 880kv xff09
  • TX2 学习记录(开启板载/USB摄像头)

    刚拿到手一个TX2 xff0c 简单地学习一下这块板子 xff0c 因为是学长留下来的板子 xff0c 所以刷机的步骤我就省略了 xff0c 各位小伙伴可以参考其他大佬的博客进行刷机 xff0c 再来就记录一下一些操作指令吧 打开USB摄像
  • ubuntu16.04中进行ROS通信编程

    ROS通信学习 基础知识学习字段ROS通信小例子一 创建一个工作区二 创建一个ROS工程包三 创建通信的发 收节点四 测试程序的正确性 图像ROS通信小例子视频ROS通信小例子多机ROS通信 基础知识学习 x1f31f 话题与服务的区别 话
  • 2021电赛F题智能送药小车方案分析(openMV数字识别,红线循迹,STM32HAL库freeRTOS,串级PID快速学习,小车自动返回)

    2021全国大学生电子设计竞赛F题智能送药小车 前提 xff1a 本篇文章重在分享自己的心得与感悟 xff0c 我们把最重要的部分 xff0c 摄像头循迹 xff0c 摄像头数字识别问题都解决了 xff0c 有两种方案一种是openARTm
  • CARLA常见错误解决方案以及常见的问题解决方案

    记录Linux环境 Windows环境下常见的运行自动驾驶仿真器CARLA出现的错误 问题1 问题1比较基础 xff0c 创建虚拟环境以及删除虚拟环境 conda create span class token operator span
  • cmd找不到conda以及通过cmd启用Anaconda中的Python环境(base)

    问题 xff1a 在cmd中输入python无法进入或启用python ipython conda jupyter notebook 一 解决方法 xff1a 在系统环境中添加Anaconda路径 lt 1 gt 1 打开高级系统设置 xf
  • c语言实现strcat函数

    char strcat char strDestination const char strSource 一 函数介绍 作用 xff1a 连接字符串的函数 xff0c 函数返回指针 xff0c 两个参数都是指针 xff0c 第一个参数所指向
  • C/C++的static关键字作用(转载)

    一 限制符号的作用域只在本程序文件 若变量或函数 xff08 统称符号 xff09 使用static修饰 xff0c 则只能在本程序文件内使用 xff0c 其他程序文件不能调用 xff08 非static的可以通过extern 关键字声明该
  • crc校验

    参考链接 xff1a https www cnblogs com esestt archive 2007 08 09 848856 html 一 CRC校验原理 1 CRC校验全称为循环冗余校验 xff08 Cyclic Redundanc
  • ubuntu安装eclipse教程

    在安装eclipse之前 xff0c 要先安装JDK xff0c 一 安装JDK 1 从官网上下载JDK 链接 xff1a https www oracle com java technologies downloads 选择的jdk文件一
  • UDP通信入门篇

    UDP通信属于网络通信中的一种方式 xff0c 需要用套接字来进行通信 初接触UDP通信时 xff0c 不知道需要链接静态库 pragma comment lib ws2 32 lib xff0c 导致自己在前期浪费了很多时间去排查问题 除