查看: 608|回复: 0

[评测分享] 【更适合初学者的开发板ELF 1】10-UDP编程及测试

[复制链接]
  • TA的每日心情
    奋斗
    昨天 22:50
  • 签到天数: 94 天

    连续签到: 3 天

    [LV.6]常住居民II

    发表于 2023-12-4 22:05:37 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 stm1024 于 2023-12-5 22:36 编辑

    嵌入式Linux比MCU相比一个很省心的地方就是安装了很多的库和实现了很多的协议栈,因此我们只需要在其基础上进行应用层面的开发就可以了,而不需要自己先去写驱动啥的。今天抽空把UDP编程测试一下。
    UDP是无连接的传输协议,为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。它除了给应用程序发送数据包功能并允许它们在所需的层次上架构自己的协议之外,几乎没有做什么特别的事情。相对于TCP,它的传输更高效。而且很多协议或者应用都是构建在UDP之上的,例如以前局域网内应用很广泛的飞鸽或者飞秋,都是基于UDP协议的。

    1. 编程规划
    本次需要实现一个UDP的单点程序,就是单服务端+单客户端之间的通讯,实现收发数据,服务器端运行在虚拟机上,然后客户端程序运行在ELF-1开发板上,ELF-1客户端程序经由服务端获取时间数据,然后更新自己的时间。
    当然,台式机上的客户端/服务端都有现成的网络调试助手可用,因此就没必要专门去写程序了。

    2. 编写程序
    先写个客户端程序,代码如下:
    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <time.h>
    4. #include <string.h>
    5. #include <errno.h>
    6. #include <unistd.h>
    7. #include <arpa/inet.h>
    8. #include <sys/types.h>
    9. #include <sys/socket.h>
    10. #include <sys/time.h>

    11. char rxbuf[16];
    12. char txbuf[16]="tell me time";
    13. void dispErrInfo(const char* pretext,int errcode)
    14. {
    15.     printf("%s, errno=%d: %s\n",pretext,errcode,strerror(errcode));
    16. }

    17. void setTime()
    18. {
    19.     struct timeval tv;
    20.     int ret;
    21.     time_t tt;
    22.     tv.tv_sec=*((long*)(rxbuf));
    23.     tv.tv_usec=*((long*)(rxbuf+8));
    24.    
    25.     ret=settimeofday(&tv,NULL);
    26.     if(ret<0)
    27.     {
    28.         dispErrInfo("setTime Failed",errno);
    29.     }
    30.     else
    31.     {
    32.         tt=time(NULL);
    33.         printf("Now Time is: %s\n",ctime(&tt));
    34.     }
    35. }


    36. int main()
    37. {
    38.     int sktfd = socket(PF_INET, SOCK_DGRAM, 0);
    39.     if(sktfd<0)
    40.     {
    41.         dispErrInfo("create socket failed, ",errno);
    42.         return errno;
    43.     }

    44.     //server info
    45.     struct sockaddr_in saddr;
    46.     saddr.sin_family = AF_INET;
    47.     saddr.sin_port = htons(54321);
    48.     inet_pton(AF_INET, "192.168.147.101", &saddr.sin_addr.s_addr);//hard coded
    49.     int num = 0;

    50.         sendto(sktfd, txbuf, 16, 0, (struct sockaddr *)&saddr, sizeof(saddr));
    51.         memset(rxbuf,0x00,256);
    52.         num = recvfrom(sktfd, rxbuf, 16, 0, NULL, NULL);
    53.         if(num>0)
    54.         {
    55.             setTime();
    56.         }
    57.     close(sktfd);
    58.     return 0;
    59. }
    复制代码
    注意上面使用的是192.168.147.101,这个是我虚拟机中Ubuntu18.04.5的局域网IP地址:
    Screenshot from 2023-12-05 22-24-05.png
    再写一个服务端程序,代码如下:
    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <string.h>
    4. #include <errno.h>
    5. #include <unistd.h>
    6. #include <arpa/inet.h>
    7. #include <sys/types.h>
    8. #include <sys/socket.h>
    9. #include <sys/time.h>

    10. char txbuf[16]="hithere";
    11. char rxbuf[16];

    12. void dispErrInfo(const char* pretext,int errcode)
    13. {
    14.     printf("%s, errno=%d: %s\n",pretext,errcode,strerror(errcode));
    15. }

    16. void padTime()
    17. {
    18.     struct timeval tv;
    19.     int x=gettimeofday(&tv,NULL);
    20.     printf("Timestamp:\t%ld.%ld\n",tv.tv_sec,tv.tv_usec);
    21.     memset(txbuf,0x00,16);
    22.     memmove(txbuf,&(tv.tv_sec),8);
    23.     memmove(txbuf+8,&(tv.tv_usec),8);
    24. }


    25. int main()
    26. {
    27.     int sktfd,ret,len;
    28.     struct sockaddr_in saddr;//server
    29.     struct sockaddr_in caddr;//client
    30.     sktfd=socket(AF_INET,SOCK_DGRAM,0);
    31.     if(sktfd<0)
    32.     {
    33.         dispErrInfo("create socket failed, ",errno);
    34.         return errno;
    35.     }
    36.     saddr.sin_family = AF_INET;
    37.     saddr.sin_port = htons(54321);
    38.     saddr.sin_addr.s_addr = INADDR_ANY;
    39.     ret = bind(sktfd, (struct sockaddr *)(&saddr), sizeof(saddr));
    40.     if(ret<0)
    41.     {
    42.         dispErrInfo("bind failed",errno);
    43.         return errno;
    44.     }
    45.     len = sizeof(caddr);
    46.     while(1)
    47.     {
    48.         ret=recvfrom(sktfd, rxbuf, 16, 0, (struct sockaddr *)(&caddr), (socklen_t*)(&len));
    49.         padTime();
    50.         sendto(sktfd,txbuf,16,0,(struct sockaddr *)(&caddr), sizeof(caddr));      
    51.     }
    52.     return 0;
    53. }
    复制代码

    3. 测试程序
    测试效果如下:
    先在虚拟机中运行服务器端程序:
    111.png


    然后将客户端程序使用arm-linux-gcc编译以后,下载到开发板中,并赋予其可执行权限,然后运行:
    999.png


    如果需要保存当前的时间,可以使用命令:
    hwclock -s
    使RTC时钟芯片保存当前系统时间。




    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-5-20 13:33 , Processed in 0.113805 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.