回答

收藏

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

#板卡评测 #板卡评测 1871 人阅读 | 0 人回复 | 2023-12-04

本帖最后由 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地址:

再写一个服务端程序,代码如下:
  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. 测试程序
测试效果如下:
先在虚拟机中运行服务器端程序:



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



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




分享到:
回复

使用道具 举报

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

本版积分规则

关闭

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