Win32 UDP Socket通信学习

2023-11-18

学习内容,参见《Windows网络编程》第7章 Winsock基础

 

与TCP流式协议不同,UDP为数据报协议。

 

服务端接受数据,客户端发送数据。

UDP服务端流程

  • Socket或WSASocket建立套接字,用SOCK_DGRAM标志。
  • bind绑定到IP地址和端口。
  • recvfrom/WSARecvFrom接受数据。

 

UDP客户端流程

UDP客户端有两种方式,一种为无连接,一种为创建虚拟连接。

方式一 无连接

  • Socket或WSASocket建立套接字,用SOCK_DGRAM标志。
  • 设置服务器地址和端口。
  • sento/WSASendTo发送数据。

方式二 建立虚拟连接

  • Socket或WSASocket建立套接字,用SOCK_DGRAM标志。
  • 设置服务器地址和端口。
  • connect连接服务端。
  • 调用send发送数据。

 

使用windows的Winsock 2编程,需要进行工程配置。

  • 工程右键Properties->ConfigurationProperties->Linker->Input->Additional Dependencies中添加ws2_32.lib。
  • Demo代码采用Multi-Byte方式,设置Properties->ConfigurationProperties->General->Character Set为Use Multi-Byte Character Set。

备注:所有关系到收发数据的缓冲都属于简单的char类型,这些函数没有Unicode版本。当字符集为Unicode时,需要进行字符串转换。

 

服务端源码,UDPServer.cpp。

[cpp]  view plain copy
  1. // UDPServer.cpp : Defines the entry point for the console application.  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include <WinSock2.h>  
  6. #include <stdio.h>  
  7. #include <stdlib.h>  
  8.   
  9. #define DEFAULT_PORT 5150  
  10. #define DEFAULT_COUNT 5  
  11. #define DEFAULT_BUFFER_LENGTH 4096  
  12.   
  13. int iPort = DEFAULT_PORT;  
  14. DWORD dwCount = DEFAULT_COUNT;  
  15. DWORD dwLength = DEFAULT_BUFFER_LENGTH;  
  16. BOOL bInterface = FALSE;  
  17.   
  18. char szIterface[32];  
  19.   
  20. //Print usage information and exit  
  21. void usage()  
  22. {  
  23.     printf("usage:sender[-p:int][-i:IP][-n:x][-b:x]\n\n");  
  24.     printf("      -p:int  Local port\n");  
  25.     printf("      -i:IP    Local IP address to listen on\n");  
  26.     printf("      -n:x    Number of times to send message\n");  
  27.     printf("      -b:x    Size of buffer to send \n\n");  
  28.   
  29.     ExitProcess(1);  
  30. }  
  31.   
  32. //ValidateArgs  
  33. void ValidateArgs(int argc, _TCHAR** argv)  
  34. {  
  35.     for (int i = 1; i < argc; i++)  
  36.     {  
  37.         if ((argv[i][0] == _T('-') || (argv[i][0] == _T('/'))))  
  38.         {  
  39.             switch (tolower(argv[i][1]))  
  40.             {  
  41.             case _T('p'):  
  42.                 if (_tcslen(argv[i]) > 3)  
  43.                 {  
  44.                     iPort = _ttoi(&argv[i][3]);  
  45.                 }  
  46.                 break;  
  47.             case _T('n'):  
  48.                 //Number of times to receive message  
  49.                 if (_tcslen(argv[i]) > 3)  
  50.                 {  
  51.                     dwCount = _ttol(&argv[i][3]);  
  52.                 }  
  53.                 break;  
  54.             case _T('b'):  
  55.                 //Buffer size  
  56.                 if (_tcslen(argv[i]) > 3)  
  57.                 {  
  58.                     dwLength = _ttol(&argv[i][3]);  
  59.                 }  
  60.                 break;  
  61.             case _T('i'):  
  62.                 //Interface to receive datagrams on  
  63.                 if (_tcslen(argv[i]) > 3)  
  64.                 {  
  65.                     bInterface = TRUE;  
  66.                     _tcscpy_s(szIterface, &argv[i][3]);  
  67.                 }  
  68.                 break;  
  69.             default:  
  70.                 usage();  
  71.                 break;  
  72.             }  
  73.         }  
  74.     }  
  75. }  
  76.   
  77. int _tmain(int argc, _TCHAR* argv[])  
  78. {  
  79.     //Parse arguments and load winsock  
  80.     ValidateArgs(argc, argv);  
  81.   
  82.     WSADATA wsd;  
  83.     if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)  
  84.     {  
  85.         printf("WSAStartup failed!\n");  
  86.         return 1;  
  87.     }  
  88.   
  89.     //Create the socket, and bind it to a local interface and port  
  90.     SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);  
  91.     if (s == INVALID_SOCKET)  
  92.     {  
  93.         printf("socket() failed:%d\n", WSAGetLastError());  
  94.         return 1;  
  95.     }  
  96.   
  97.     SOCKADDR_IN local;  
  98.     local.sin_family = AF_INET;  
  99.     local.sin_port = htons((short)iPort);  
  100.     if (bInterface)  
  101.     {  
  102.         local.sin_addr.s_addr = inet_addr(szIterface);  
  103.     }  
  104.     else  
  105.     {  
  106.         local.sin_addr.s_addr = htonl(INADDR_ANY);  
  107.     }  
  108.   
  109.     if (bind(s, (SOCKADDR*)&local, sizeof(local)) == SOCKET_ERROR)  
  110.     {  
  111.         printf("bind() failed:%d\n", WSAGetLastError());  
  112.         return 1;  
  113.     }  
  114.   
  115.     //Allocate the receive buffer  
  116.     char* recvbuf = (char*)GlobalAlloc(GMEM_FIXED, dwLength);  
  117.     if (!recvbuf)  
  118.     {  
  119.         printf("GlobalAlloc() failed:%d\n", GetLastError());  
  120.         return 1;  
  121.     }  
  122.   
  123.     //Read the datagrams  
  124.     SOCKADDR_IN sender;  
  125.     for (int i = 0; i < (int)dwCount; i++)  
  126.     {  
  127.         int nSenderSize = sizeof(sender);  
  128.         int ret = recvfrom(s, recvbuf, dwLength, 0,  
  129.             (SOCKADDR*)&sender, &nSenderSize);  
  130.         if (ret == SOCKET_ERROR)  
  131.         {  
  132.             printf("recvfrom() failed:%d\n", WSAGetLastError());  
  133.             break;  
  134.         }  
  135.         else if (ret == 0)  
  136.         {  
  137.             break;  
  138.         }  
  139.         else  
  140.         {  
  141.             recvbuf[ret] = _T('\0');  
  142.             printf("[%s] sent me:'%s'\n",  
  143.                 inet_ntoa(sender.sin_addr), recvbuf);  
  144.         }  
  145.     }  
  146.     closesocket(s);  
  147.   
  148.     GlobalFree(recvbuf);  
  149.     WSACleanup();  
  150.     return 0;  
  151. }  

客户端源码,UDPClient.cpp。

[cpp]  view plain copy
  1. // UDPClient.cpp : Defines the entry point for the console application.  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include <WinSock2.h>  
  6. #include <stdio.h>  
  7. #include <stdlib.h>  
  8.   
  9. #define DEFAULT_PORT 5150  
  10. #define DEFAULT_COUNT 25  
  11. #define DEFAULT_CHAR 'a'  
  12. #define DEFAULT_BUFFER_LENGTH 32  
  13.   
  14. BOOL bConnect = FALSE;  
  15. int iPort = DEFAULT_PORT;  
  16. char cChar = DEFAULT_CHAR;  
  17. DWORD dwCount = DEFAULT_COUNT;  
  18. DWORD dwLength = DEFAULT_BUFFER_LENGTH;  
  19. char szRecipient[128];  
  20.   
  21. //Print usage information and exit  
  22. void usage()  
  23. {  
  24.     printf("usage:sender[-p:int][-r:IP][-c][-n:x][-b:x][-d:c]\n\n");  
  25.     printf("      -p:int    Remote port\n");  
  26.     printf("      -r:IP     Recipient's IP address or host name\n");  
  27.     printf("      -c         Connect to remote IP first\n");  
  28.     printf("      -n:x     Number of times to send message\n");  
  29.     printf("      -b:x     Size of buffer to send\n");  
  30.     printf("      -d:c     Character to fill buffer with\n\n");  
  31.     ExitProcess(1);  
  32. }  
  33.   
  34. //Parse the command line arguments, and set some global flags to  
  35. //indicate what actions to perform  
  36. void ValidateArgs(int argc, _TCHAR** argv)  
  37. {  
  38.     for (int i = 1; i < argc; i++)  
  39.     {  
  40.         if ((argv[i][0] == _T('-') || (argv[i][0] == _T('/'))))  
  41.         {  
  42.             switch (tolower(argv[i][1]))  
  43.             {  
  44.             case _T('p'):  
  45.                 //Remote port  
  46.                 if (_tcslen(argv[i]) > 3)  
  47.                 {  
  48.                     iPort = _ttoi(&argv[i][3]);  
  49.                 }  
  50.                 break;  
  51.             case _T('r'):  
  52.                 //Recipient's IP addr  
  53.                 if (_tcslen(argv[i]) > 3)  
  54.                 {  
  55.                     _tcscpy_s(szRecipient, &argv[i][3]);  
  56.                 }  
  57.                 break;  
  58.             case _T('c'):  
  59.                 //Connect to recipient's IP addr  
  60.                 bConnect = TRUE;  
  61.                 break;  
  62.             case _T('n'):  
  63.                 if (_tcslen(argv[i]) > 3)  
  64.                 {  
  65.                     dwCount = _ttol(&argv[i][3]);  
  66.                 }  
  67.                 break;  
  68.             case _T('b'):  
  69.                 if (_tcslen(argv[i]) > 3)  
  70.                 {  
  71.                     dwLength = _ttol(&argv[i][3]);  
  72.                 }  
  73.                 break;  
  74.             case _T('d'):  
  75.                 cChar = argv[i][3];  
  76.                 break;  
  77.             default:  
  78.                 usage();  
  79.                 break;  
  80.             }  
  81.         }  
  82.     }  
  83. }  
  84.   
  85. int _tmain(int argc, _TCHAR* argv[])  
  86. {  
  87.     ValidateArgs(argc, argv);  
  88.   
  89.     WSADATA wsd;  
  90.     if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)  
  91.     {  
  92.         printf("WSAStartup failed!\n");  
  93.         return 1;  
  94.     }  
  95.   
  96.     //Crate the socket  
  97.     SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);  
  98.     if (s == INVALID_SOCKET)  
  99.     {  
  100.         printf("socket() failed:%d\n", WSAGetLastError());  
  101.         return 1;  
  102.     }  
  103.   
  104.     //Resolve the recipient's IP address or host name  
  105.     SOCKADDR_IN recipient;  
  106.     recipient.sin_family = AF_INET;  
  107.     recipient.sin_port = htons((short)iPort);  
  108.   
  109.     int nServerLen = (int)_tcslen(szRecipient);  
  110.     if (0 == nServerLen)  
  111.     {  
  112.         struct hostent* host = gethostbyname(szRecipient);  
  113.         if (host == NULL)  
  114.         {  
  115.             printf("gethostbyname() failed:%d\n", WSAGetLastError());  
  116.             WSACleanup();  
  117.             return 1;  
  118.         }  
  119.   
  120.         CopyMemory(&recipient.sin_addr, host->h_addr_list[0], host->h_length);  
  121.     }  
  122.     else  
  123.     {  
  124.         recipient.sin_addr.s_addr = inet_addr(szRecipient);  
  125.     }  
  126.   
  127.     //Allocate the send buffer  
  128.     char* sendbuf = (char*)GlobalAlloc(GMEM_FIXED, dwLength);  
  129.     if (!sendbuf)  
  130.     {  
  131.         printf("GlobalAlloc() failed:%d\n", GetLastError());  
  132.         return 1;  
  133.     }  
  134.     memset(sendbuf, cChar, dwLength);  
  135.   
  136.     if (bConnect)  
  137.     {  
  138.         //If the connect option is set, "connect" to the recipient  
  139.         //and send the data with the send() fuction  
  140.   
  141.         if (connect(s, (SOCKADDR*)&recipient,  
  142.             sizeof(recipient)) == SOCKET_ERROR)  
  143.         {  
  144.             printf("connect() failed:%d\n", WSAGetLastError());  
  145.             GlobalFree(sendbuf);  
  146.             WSACleanup();  
  147.             return 1;  
  148.         }  
  149.   
  150.         for (int i = 0; i < (int)dwCount; i++)  
  151.         {  
  152.             int ret = send(s, sendbuf, dwLength, 0);  
  153.             if (ret == SOCKET_ERROR)  
  154.             {  
  155.                 printf("send() failed:%d\n", WSAGetLastError());  
  156.                 break;  
  157.             }  
  158.             else if (ret == 0)  
  159.             {  
  160.                 break;  
  161.             }  
  162.         }  
  163.     }  
  164.     else  
  165.     {  
  166.         //Otherwise, use the sendto() function  
  167.         for (int i = 0; i < (int)dwCount; i++)  
  168.         {  
  169.             int ret = sendto(s, sendbuf, dwLength, 0,  
  170.                 (SOCKADDR*)&recipient, sizeof(recipient));  
  171.             if (ret == SOCKET_ERROR)  
  172.             {  
  173.                 printf("send() failed:%d\n", WSAGetLastError());  
  174.                 break;  
  175.             }  
  176.             else if (ret == 0)  
  177.             {  
  178.                 break;  
  179.             }  
  180.         }  
  181.     }  
  182.   
  183.     closesocket(s);  
  184.     GlobalFree(sendbuf);  
  185.     WSACleanup();  
  186.     return 0;  
  187. }  

http://blog.csdn.net/segen_jaa/article/details/7565689


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

Win32 UDP Socket通信学习 的相关文章

  • 《软件调试的艺术》学习笔记——GDB使用技巧摘要(3)——程序崩溃处理

    程序为什么会崩溃 内存中的程序布局 当某个错误导致程序突然和异常地停止执行时 程序崩溃 迄今为止最为常见的导致程序崩溃的原因是试图在未经允许的情况下访问一个内存位置 硬件会感知这件事 并执行对操作系统的跳转 Unix系列的平台上 操作系统一
  • VS2015下用Qt Designer创建对话框

    目录 1 Qt Designer新建文件 选择适合的模板 布局窗口 2 在右侧属性窗口修改名称为需要的名称 3 文件另存为对象名称一样的xxx ui文件 4 创建xxx cpp和xxx h文件 加入工程 也可以在qt creator中创建
  • sql-labs闯关38~45

    sql labs闯关38 45 友善爱国平等诚信民主友善爱国爱国友善平等诚信自由平等友善平等法治诚信民主民主 复习笔记1 内容 sql labs第38关 GET请求 堆叠查询注入 字符型 sql labs第39关 GET请求 堆叠查询注入
  • 30分钟从零开始搭建并部署个人知识库(超详细)

    前言 网上关于动态文档生成工具有很多如 Docsify VuePress Docute Hexo这些都是一些非常优秀的文档生成工具 本章主要介绍如何快速使用Docsify搭建一个快捷 轻量级的个人 团队文档 并且通过Github Pages
  • dracut 基本介绍

    dracut 基本介绍 dracut 维基 https dracut wiki kernel org index php Main Page http www 360doc com content 13 0428 09 12139495 2

随机推荐

  • 计算机网络系列五 -- 运输层详解

    1 运输层 1 1 运输层的定义 运输层是 OSI 七层参考模型的第四层 主要功能为应用层提供通信服务 它即是面向通信的最高层 也是用户功能的最底层 在计算机网络中 真正进行数据通信的是两个主机的进程 由于一个主机中有多个进程同时在通信 而
  • vc++画线段的函数_word2vec的损失函数

    虽然word2vec常被当作无监督 但是其训练过程跟有监督基本差不多 原始的word2vec暂时不考虑负采样和huffman tree 其损失函数就是多元交叉熵 多元交叉熵的公式 以传统机器学习来说 这里的Zj就是某个类别的预测概率 yj
  • 物联网嵌入式学习路线发展方向(表格一目了然)

    文章目录 一 学习路线 二 各种分类 1 软件硬件分类 2 发展方向 技术类型 对应岗位分类 2 1 芯片方向 2 2 Linux方向 3 常见板子芯片内核 4 嵌入式公司 对于小白 不知道嵌入式整个体系 学什么 顺序是什么 可以找什么工作
  • Review-MyBatis

    MyBatis 1 学习方法 MyBatis框架功能与Hibernate一样 都是持久化框架 都是操作JDBC 做ORM框架 1 MyBatis框架比Hibernate小 2 做的是针对SQL语句查询结果进行封装 2 MyBatis框架是什
  • 服务器磁盘性能多少分正常,服务器内存使用率多少为正常

    服务器内存使用率多少为正常 内容精选 换一换 当您发现云服务器的运行速度变慢或云服务器突然出现网络断开现象 则可能是云服务器的带宽和CPU使用率过高导致 如果您已经通过云监控服务创建过告警任务 当CPU或带宽利用率高时 系统会自动发送告警给
  • 微弱直流电压/电流信号的采样电路 --滤波跟随放大

    要求将待测的电压 1mV 1000mV 电流 1mA 100mA 采样出来传给单片机 我的思路是 电压采样先用放大电路放大 再进行滤波 把50Hz的交流电干扰滤除 然后再进行模数转换传给单片机 电流的话用一个采样电阻 然后对其电压采样后推算
  • 信息学奥赛一本通【1034:计算三角形面积】

    题目描述 平面上有一个三角形 它的三个顶点坐标分别为 x1 y1 x2 y2 x3 y3 x1 y1 x2 y2 x3 y3 那么请问这个三角形的面积是多少 精确到小数点后两位 输入 输入仅一行 包括66个单精度浮点数 分别对应x1 y1
  • 关于git的一些命令,实验记录

    1 下载moduleA项目代码 命令 git clone https github com wangyanan52121 moduleA git 因网络问题 可能会下载失败 多试几次 2 查看当前项目 查看tag命令 字符串排序 git C
  • 语言深入理解指针(非常详细)(三)

    目录 数组名的理解 使用指针访问数组 一维数组传参的本质 二级指针 指针数组 指针数组模拟二维数组 数组名的理解 在上 个章节我们在使用指针访问数组的内容时 有这样的代码 int arr 10 1 2 3 4 5 6 7 8 9 10 in
  • mysql如何一秒插入10万条数据

    当我们需要批量插入或者更新记录时 可以采用Java的批量更新机制 该机制允许多条语句甚至一次性提交给数据库处理 通常情况下比一句一提交处理更有效率 jdbc处理批量提交有三个方法 需要注意的是 这三种方法都要和PreparedStateme
  • Rx与Async Task的简单对比

    有关Reactive Extensions的介绍可见https rx codeplex com 总的来说 你可以当它是又一个异步编程的框架 它以观察者模式实现了对数据流的的 订阅 一个列表 一个事件 一个耗时操作的方法 等等 都可以Obse
  • C++ 多线程std::async

    std async 对于线程的创建 我们可以直接用thread 但是这会有很多的不便 比如获取子进程的返回值 解决方案是定义一个变量 然后将变量的指针传入到子进程中 然后对其进行赋值 但终归是不便 除此之外我们可以用std async函数来
  • 如何正确理解开漏输出和推挽输出

    作者 知乎用户 链接 https www zhihu com question 28512432 answer 41217074 来源 知乎 著作权归作者所有 商业转载请联系作者获得授权 非商业转载请注明出处 我觉得下面这个 网上资料 还是
  • java项目如何实现数据恢复_Java web 项目中对数据库备份和恢复

    说白了 还是去调用cmd实现数据库的备份和还原功能 备份 mysqldump hserverUrl uusername ppassword dbname gt savePath 还原 mysql hserverUrl uusername p
  • 一文读懂SpringCloud全家桶

    一 云原生应用 SpringCloud是对Springboot使用的分布式解决方案 适合分布式 中大型的项目架构开发 现在也逐渐成为Java服务端的主流框架 使用Spring Cloud开发的应用程序非常适合在Docker和PaaS 比如P
  • C# 提交报错:Validation of viewstate MAC failed 解决办法

    出现以下报错 验证视图状态 MAC 失败 如果此应用程序由网络场或群集承载 请确保
  • 【STM32】SPI初步使用 读写FLASH W25Q64

    硬件连接 1 SS Slave Select 从设备选择信号线 常称为片选信号线 每个从设备都有独立的这一条 NSS 信号线 当主机要选择从设备时 把该从设备的 NSS 信号线设置为低电平 该从设备即被选中 即片选有效 接着主机开始与被选中
  • MySQL 8.0 多实例的配置应用

    文章目录 同版本多实例 配置 部署 启动 连接 不同版本多实例 配置 初始化 initialize insecure 含义 启动 同版本多实例 配置 mkdir p data 330 7 9 data chown R mysql mysql
  • 同城双活与异地多活架构分析

    本文首发于 vivo互联网技术 微信公众号 链接 https mp weixin qq com s OjfFcjnGWV5kutxXndtpMg 作者 vivo官网商城开发团队 采用高可用系统架构支持重要系统 为关键业务提供7x24的不间断
  • Win32 UDP Socket通信学习

    学习内容 参见 Windows网络编程 第7章 Winsock基础 与TCP流式协议不同 UDP为数据报协议 服务端接受数据 客户端发送数据 UDP服务端流程 Socket或WSASocket建立套接字 用SOCK DGRAM标志 bind