• 网络与通信程序设计-基于UDP的广播通信实例


    目录

    实验内容和设计思想

    实验的内容

    UDP的设计思想

    UDP的协议头部

    UDP通信编程思想

    UDP的工作流程

    UDP编程收发函数

    广播通信

    广播模式设置

    广播套接字

    UDP Socket的使用过程

    UDP广播通信实例实现

    initsock.h

    服务器发送广播消息

    客户端接收广播消息

    运行效果

    实验心得 


    实验内容和设计思想

    通过本文的学习,希望可以帮助大家完成一个简易的基于UDP的广播通信实例

    实验的内容

    编写基于广播通信模型的服务器端和客户端通信程序,要求编程实现服务器端与客户端之间广播数据传递。服务器端向所有客户端发送今天是个好日子!”广播消息,客户端收到并在本地显示给用户。

    UDP的设计思想

    由于UDP协议本身异常简单,实际上只为IP传输起到了桥梁的作用,在一些场景上通过【 应用层->UDP->IP 】的封装方式,可以极大的提高程序调用效率。

    UDP(User Datagram Protocol)传输与IP传输非常类似。你可以将UDP协议看作IP协议暴露在传输层的一个接口。UDP协议同样以数据包(datagram)的方式传输,它的传输方式也是"Best Effort"的,所以UDP协议也是不可靠的(unreliable)。

    UDP是一个无连接协议,传输数据之前源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。

    由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等,因此一台服务机可同时向多个客户机传输相同的消息。

    UDP的协议头部

    source port出发端口
    destination port目的地端口
    LengthUDP包的长度
    ChecksumIP协议的header checksum算法相类似


    UDP通信编程思想

    UDP的工作流程

    UDP 用户数据报协议提供的是无连接的、不可靠的数据传输服务,但是不需要像 TCP 那样建立连接,所以传输效率高。

     对比TCP的工作流程

    UDP编程收发函数

    UDP编程的数据收发函数为sendto()和recvfrom()

    1. int sendto(
    2. SOCKET s, //发送数据的套接字
    3. const char FAR * buf, //发送数据的缓冲区
    4. int len, //发送数据的长度
    5. int flags, //一般指定为0
    6. const struct sockaddr FAR * to, //指向一个包含目标地址和端口号的sockaddr_in结构
    7. int tolen //为sockaddr_in结构的大小
    8. );

    同样的接收数据的函数是 recvfrom(),UDP接收数据时也需要知道通信对端的地址信息。

    int recvfrom(SOCKET s,char FAR*buf,int len,int flag,struct sockaddr_in FAR*from,int FAR*fromlen)

    广播通信

    利用广播(broadcast)可以将数据发送给本地子网上的每个机器,同时需要有一些线程在机器上监听到来的数据。广播的缺点是如果多个进程都发送广播数据,网络就会阻塞,网络性能便会受到影响。

    利用广播(broadcast)可以将数据发送给本地子网上的每个机器。

    广播模式设置

    广播套接字

    获取和设置套接字选项的函数分别是 getsockopt() 和 setsockopt(),函数调用出错时返回 SOCKET ERROR。

    1. int setsockopt(
    2. SOCKET s,
    3. int level,
    4. int optname,
    5. const char FAR * optval,
    6. int* optlen
    7. );

    参数说明:

    同理接收套接字也采用类似于setsockopt的定义模式

    int getsockopt(SOCKET s,int level, optname, const char FAR * optval,int* optlen);

    此外,进行广播通信,必须打开广播选项SO_BROADCAST为True。

    SOBROADCAST 选项设置套接字传输和接收广播消息,如果给定套接字已经被设置为接收或者发送广播数据,查询此套接字选项将返回TRUE,此选项对于那些不是SOCK_STREAM类型的套接字有效。

    1. SOCKET s = ::socket(AF_INET, SOCK_DGRAM, 0);
    2. // 有效SO_BROADCAST选项
    3. BOOL bBroadcast = TRUE;
    4. ::setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&bBroadcast, sizeof(BOOL));

    UDP Socket的使用过程

    1. 初始化网络库

    2. 创建SOCK_DGRAM类型的Socket。

    3. 绑定套接字。

    4. 发送、接收数据。

    5. 销毁套接字。

    6. 释放网络库。


    UDP广播通信实例实现

    实现服务器端与客户端之间广播数据传递,服务器端向所有客户端发送“今天是个好日子!”广播消息,客户端收到并在本地显示。

    initsock.h

    1. #include
    2. #pragma comment(lib, "WS2_32") // 链接到 WS2_32.lib
    3. class CInitSock
    4. {
    5. public:
    6. /*CInitSock 的构造器*/
    7. CInitSock(BYTE minorVer = 2, BYTE majorVer = 2)
    8. {
    9. // 初始化WS2_32.dll
    10. WSADATA wsaData;
    11. WORD sockVersion = MAKEWORD(minorVer, majorVer);
    12. if (::WSAStartup(sockVersion, &wsaData) != 0)
    13. {
    14. exit(0);
    15. }
    16. }
    17. /*CInitSock 的析构器*/
    18. ~CInitSock()
    19. {
    20. ::WSACleanup();
    21. }
    22. };

    服务器发送广播消息

    对于 UDP 来说存在一个特定的广播地址 255.255.255.255,广播数据都应该发送到这里。发送方程序在创建套接字后使用 setsockopt 函数打开 SO_BROADCAST选项,然后设置广播地址 255.255.255.255,使用 sendto 函数向端口号 54321 不断发送广播数据。

    1. #include "initsock.h"
    2. #include
    3. #include
    4. using namespace std;
    5. CInitSock theSock;
    6. int main()
    7. {
    8. SOCKET s = ::socket(AF_INET, SOCK_DGRAM, 0);
    9. // 有效SO_BROADCAST选项
    10. BOOL bBroadcast = TRUE;
    11. ::setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&bBroadcast, sizeof(BOOL));
    12. // 设置广播地址和广播端口号
    13. SOCKADDR_IN bcast;
    14. bcast.sin_family = AF_INET;
    15. bcast.sin_port = htons(54321);
    16. bcast.sin_addr.s_addr = INADDR_BROADCAST;
    17. // 发送广播
    18. cout << " 开始向端口发送广播数据... \n" << endl;
    19. char sz[] = "今天是个好日子! \r\n";
    20. while (TRUE)
    21. {
    22. time_t now = time(0); // 基于当前系统的当前日期/时间
    23. char* dt = ctime(&now);
    24. ::sendto(s, sz, strlen(sz), 0, (sockaddr*)&bcast, sizeof(bcast));
    25. cout << dt << "发送广播:" << sz << endl;
    26. ::Sleep(5000);
    27. }
    28. return 0;
    29. }

    客户端接收广播消息

    使用 recvfrom 函数,向端口号 54321 接收广播数据。

    1. #include "initsock.h"
    2. #include
    3. #include
    4. using namespace std;
    5. CInitSock theSock;
    6. int main()
    7. {
    8. SOCKET s = ::socket(AF_INET, SOCK_DGRAM, 0);
    9. // 首先要绑定一个本地地址,指明广播端口号
    10. SOCKADDR_IN sin;
    11. sin.sin_family = AF_INET;
    12. sin.sin_port = htons(54321);
    13. sin.sin_addr.S_un.S_addr = INADDR_ANY;
    14. if (::bind(s, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)
    15. {
    16. cout << " bind() failed!" << endl;
    17. return 0;
    18. }
    19. // 接收广播
    20. cout << " 开始在端口接收广播数据... \n" << endl;
    21. SOCKADDR_IN addrRemote;
    22. int nLen = sizeof(addrRemote);
    23. char sz[256];
    24. while (TRUE)
    25. {
    26. int nRet = ::recvfrom(s, sz, 256, 0, (sockaddr*)&addrRemote, &nLen);
    27. if (nRet > 0)
    28. {
    29. sz[nRet] = '\0';
    30. time_t now = time(0); // 基于当前系统的当前日期/时间
    31. char* dt = ctime(&now);
    32. cout << dt << "接收到广播:" << sz << endl;
    33. }
    34. }
    35. return 0;
    36. }

    运行效果

    实验心得 

    1,为了进行广播通信,必须打开广播选项SO_BROADCAST

    2,接收方一定要知道广播方的端口号,然后绑定此端口号才能正确接收。

    3,UDP(User Datagram Protocol)传输与IP传输非常类似。你可以将UDP协议看作IP协议暴露在传输层的一个接口。UDP协议同样以数据包(datagram)的方式传输,它的传输方式也是"Best Effort"的,所以UDP协议也是不可靠的(unreliable)。

    4,由于UDP协议本身异常简单,实际上只为IP传输起到了桥梁的作用,在一些场景上通过应用层->UDP->IP的封装方式,可以极大的提高程序调用效率。

    5,UDP是一个无连接协议,传输数据之前源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。

    由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等,因此一台服务机可同时向多个客户机传输相同的消息。

  • 相关阅读:
    STM32使用库函数点灯实验
    6.S081 附加Lab4 从源代码看进程退出——exit,wait,kill
    [Shell详解-7]:循环语句
    日本大阪大学万伟伟研究员介绍基于WRS系统机器人的快速集成方法和应用
    DCDC直流低压升高压隔离电源模块(带短路保护)
    12、Java——对象和类案例代码详解
    python+pytorch人脸表情识别
    你了解TCP协议吗(二)?
    Python 异常
    面前是惊涛骇浪:对当下的经济困境,货币政策和大类资产的看法
  • 原文地址:https://blog.csdn.net/weixin_51989356/article/details/128048982