基于TCP实现文件传输与UDP编程示例-RZMPU工业控制教程连载(19)

瑞萨MCU小百科 2024-09-29 12:01

8.4 基于TCP实现文件传输

基于TCP协议,实现文件传输。约定规则:先传输一个结构体,里面含有“文件名,文件大小”


1

Client:

  1. open文件,得到文件状态(大小),构造结构体,发送结构体。

  2. 循环read文件,发送网络数据。


2

Server:

  1. 读网络数据,得到结构体,创建文件。

  2. 循环read网络数据,写文件,数量足够就关闭文件。


8.4.1 获取文件信息


本节源码位于如下目录:


关键代码:

左右滑动查看完整内容

/* ./file_stat 1.txt */int main(int argc, char **argv){ struct stat statbuf; if (argc != 2) { printf("Usage: %s \n", argv[0]); return -1; } /* 1. open */ int fd = open(argv[1], O_RDONLY); if (-1 == fd) { printf("can't open %s\n", argv[1]); return -1; } /* 2. fstat */ if (fstat(fd, &statbuf) == -1) { printf("can't get stat of %s\n", argv[1]); return -1; }           /* 3. printf */        printf("file size = %d\n", statbuf.st_size);         return 0;        }


实验方法:

gcc -o file_stat file_stat.cecho 123 > 1.txt./file_stat 1.txt



8.4.2 本地读文件、写文件


本节源码位于如下目录:


关键代码:

左右滑动查看完整内容

/* 4. 创建目标文件 */ int fd2 = open(argv[2], O_CREAT|O_WRONLY|O_TRUNC); if (-1 == fd2) { printf("can't create %s\n", argv[2]); return -1; }  while (1) { /* 读原文件 */ unsigned char c; if (read(fd, &c, 1) != 1) break; /* 写目标文件 */ if (write(fd2, &c, 1) != 1) break; }


上机实验:

左右滑动查看完整内容

编译程序: gcc -o mycp mycp.c生成大的测试文件:dd if=/dev/zero of=tmp.txt bs=1024 count=10240测试:date ; ./mycp tmp.txt tmp6.txt ; date


8.4.3 实现网络传输:传输文件信息


本节源码位于如下目录:

06_源码\8.4.2_本地读文件、写文件


源码为“netcp1_info”

 

netcp程序:

左右滑动查看完整内容

28 int main(int argc, char **argv)29 {30 int iSocketClient;31 struct sockaddr_in tSocketServerAddr;3233 int iRet;34 unsigned char ucSendBuf[1000];35 int iSendLen;3637 if (argc != 4)38 {39 printf("Usage:\n");40 printf("%s   \n", argv[0]);41 return -1;42 }4344 iSocketClient = socket(AF_INET, SOCK_STREAM, 0);// 创建一个套接字4546 tSocketServerAddr.sin_family = AF_INET;47 tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short*/48 //tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;49 if (0 == inet_aton(argv[2], &tSocketServerAddr.sin_addr))50 {51 printf("invalid server_ip\n");52 return -1;53 }54 memset(tSocketServerAddr.sin_zero, 0, 8);555657 iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));// 尝试连接到服务器58 if (-1 == iRet)59 {60 printf("connect error!\n");61 return -1;62 }6364 /* 获得文件信息 */65 struct stat statbuf;6667 int fd = open(argv[1], O_RDONLY);// 打开第一个参数指定的本地文件68 if (-1 == fd)69 {70 printf("can't open %s\n", argv[1]);71 return -1;72 }7374 if (fstat(fd, &statbuf) == -1)// 获取文件信息(大小)75 {76 printf("can't get stat of %s\n", argv[1]);77 return -1;78 }7980 /* 发送文件信息 */81 struct netcp_info info;82 info.len = statbuf.st_size;83 strcpy(info.name, argv[3]);84 //将 info 结构发送到服务器85 iSendLen = send(iSocketClient, &info, sizeof(info), 0);86 if (iSendLen <= 0)87 {88 close(iSocketClient);89 return -1;90 }91 else92 {93 printf("send %d datas, %ld\n", iSendLen, sizeof(info));94 }959697 return 0;98 }


server程序:

左右滑动查看完整内容

43 signal(SIGCHLD,SIG_IGN);// 忽略子进程结束信号,防止出现僵尸进程。4445 iSocketServer = socket(AF_INET, SOCK_STREAM, 0);//创建一个 IPv4 的 TCP 套接字46 if (-1 == iSocketServer)47 {48 printf("socket error!\n");49 return -1;50 }51 //结构体设置为接受任何 IP 的连接请求52 tSocketServerAddr.sin_family = AF_INET;53 tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short*/54 tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;55 memset(tSocketServerAddr.sin_zero, 0, 8);5657 iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));// 将套接字与特定的 IP 地址和端口号绑定58 if (-1 == iRet)59 {60 printf("bind error!\n");61 return -1;62 }6364 iRet = listen(iSocketServer, BACKLOG);// 函数使服务器的套接字进入监听状态65 if (-1 == iRet)66 {67 printf("listen error!\n");68 return -1;69 }7071 while (1) //服务器将持续运行,等待客户端的连接请求72 {73 iAddrLen = sizeof(struct sockaddr);74 iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);// 等待客户端的连接请求,并创建一个新的套接字用于与客户端通信75 if (-1 != iSocketClient)76 {77 iClientNum++;78 printf("Get connect from client %d : %s\n", iClientNum, inet_ntoa(tSocketClientAddr.sin_addr));79 if (!fork())//创建子进程来处理客户端请求,父进程继续监听其他客户端的连接请求80 {81 /* 读 100 字节的文件信息 */82 struct netcp_info info;83 //收客户端发送的文件信息,包括文件长度和文件名84 iRecvLen = recv(iSocketClient, &info, sizeof(info), 0);85 if (iRecvLen <= 0)86 {87 close(iSocketClient);88 return -1;89 }90 else91 {92 printf("Get file info From Client %d: file len =%ld, file name = %s\n", iClientNum, info.len, info.name);93 }9495 }96 }97 }


编译:

左右滑动查看完整内容

source /opt/remi-sdk/environment-setup-aarch64-poky-linux$CC netcp.c -o netcp$CC server.c -o server


假设设置开发板的IP为:192.168.5.9,上传程序到开发板上。

scp ./server root@192.168.5.9:/mnt/scp ./netcp root@192.168.5.9:/mnt/


测试:

进入/mnt目录运行程序:

root@myir-remi-1g:~# cd /mnt/root@myir-remi-1g:/mnt# lsserver netcp


在运行程序前,请先创建txt文件,写入任意数据至文件中,用于后续文件传输。

左右滑动查看完整内容

root@myir-remi-1g:/mnt# touch 1.txtroot@myir-remi-1g:/mnt# echo 123 > 1.txt


后台运行服务程序,运行客户端程序进行文件信息传输。

左右滑动查看完整内容

root@myir-remi-1g:/mnt# ./server &root@myir-remi-1g:/mnt# ./netcp 1.txt 127.0.0.1 2.txtGet connect from client 0 : 127.0.0.1send 104 datas, 104Get file info From Client 0: file len = 4, file name = 2.txt


运行程序后,可以看到终端输出文件信息内容。


注意:如果修改server.c,再次编译、运行前,先关闭之前的sever程序。命令为:killall server。


8.4.4 实现网络传输:传输文件数据


本节源码位于如下目录:


源码为“netcp2_info”


netcp程序:

左右滑动查看完整内容

80 /* 发送文件信息 */81 struct netcp_info info;82 info.len = statbuf.st_size;83 strcpy(info.name, argv[3]);8485 iSendLen = send(iSocketClient, &info, sizeof(info), 0);//发送文件信息86 if (iSendLen <= 0)87 {88 close(iSocketClient);89 return -1;90 }91 else92 {93 printf("send %d datas, %ld\n", iSendLen, sizeof(info));94 }9596 /* 传输数据 */97 unsigned char buf[1024];98 uint64_t total_len = 0;99 while (1)100 {101 /* 读原文件 */102 //unsigned char c;103 //if (read(fd, &c, 1) != 1)104 // break;105 int len;106 len = read(fd, buf, 1024);107 if (len <= 0)108 break;109 else110 {111 /* 通过网络发送给服务器 */112 iSendLen = send(iSocketClient, buf, len, 0);113 if (iSendLen != len)114 {115 close(iSocketClient);116 return -1;117 }118 //printf("send ok %d\n", iSendLen);119120 }121 }122 return 0;123 }


server程序:

左右滑动查看完整内容

72 while (1)73 {74 iAddrLen = sizeof(struct sockaddr);75 iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);76 if (-1 != iSocketClient)77 {78 iClientNum++;79 printf("Get connect from client %d : %s\n", iClientNum, inet_ntoa(tSocketClientAddr.sin_addr));80 if (!fork())81 {82 /* 读 100 字节的文件信息 */83 struct netcp_info info;8485 iRecvLen = recv(iSocketClient, &info, sizeof(info), 0);86 if (iRecvLen <= 0)87 {88 close(iSocketClient);89 return -1;90 }91 else92 {93 printf("Get file info From Client %d: file len =%ld, file name = %s\n", iClientNum, info.len, info.name);94 }9596 /* 创建文件 */97 int fd = open(info.name, O_CREAT|O_WRONLY|O_TRUNC, 0666);98 if (-1 == fd)99 {100 printf("can't create %s\n", info.name);101 return -1;102 }103 /* 接收网络数据,写文件 */104 unsigned char buf[1024];105 uint64_t writelen = 0;106107 while (1)108 {109 iRecvLen = recv(iSocketClient, buf, 1024, 0);110 if (iRecvLen <= 0)111 {112 close(iSocketClient);113 return -1;114 }115 else116 {117 if (write(fd, buf, iRecvLen) != iRecvLen)118 {119 printf("can not write file\n");120 return -1;121 }122 writelen += iRecvLen;123 if (writelen == info.len)124 {125 /* 接收到所有数据并且成功写入 */126 printf("get file %s ok\n", info.name);127 close(fd);128 return 0;129 }


编译:

左右滑动查看完整内容

source /opt/remi-sdk/environment-setup-aarch64-poky-linux$CC netcp.c -o netcp$CC server.c -o server


假设设置开发板的IP为:192.168.5.9,上传程序到开发板上。


测试:

进入/mnt目录运行程序:

root@myir-remi-1g:~# cd /mnt/root@myir-remi-1g:/mnt# lsserver netcp


在运行程序前,请先创建txt文件,写入任意数据至文件中,用于后续文件传输。

左右滑动查看完整内容

root@myir-remi-1g:/mnt# touch 1.txtroot@myir-remi-1g:/mnt# echo 123 > 1.txt


后台运行服务程序,运行客户端程序进行文件信息传输。

左右滑动查看完整内容

root@myir-remi-1g:/mnt# ./server &root@myir-remi-1g:/mnt# ./netcp 1.txt 127.0.0.1 2.txtsend 104 datas, 104Get connect from client 0 : 127.0.0.1Get file info From Client 0: file len = 4, file name = 2.txtget file 2.txt ok


运行程序后,可以看到终端输出文件数据获取成功。


注意:如果修改server.c,再次编译、运行前,先关闭之前的sever程序。命令为:killall server。



8.5 UDP编程示例

本节源码位于如下目录:


Client程序:

左右滑动查看完整内容

34 iSocketClient = socket(AF_INET, SOCK_DGRAM, 0);3536 tSocketServerAddr.sin_family = AF_INET;37 tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short*/38 //tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;39 if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))40 {41 printf("invalid server_ip\n");42 return -1;43 }44 memset(tSocketServerAddr.sin_zero, 0, 8);4546 #if 047 iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));48 if (-1 == iRet)49 {50 printf("connect error!\n");51 return -1;52 }53 #endif5455 while (1)56 {57 if (fgets(ucSendBuf, 999, stdin)) //从标准输入读取用户输入的数据。58 {59 #if 060 iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);61 #else62 iAddrLen = sizeof(struct sockaddr);63 iSendLen = sendto(iSocketClient, ucSendBuf, strlen(ucSendBuf),0,64 (const struct sockaddr *)&tSocketServerAddr, iAddrLen);// 将数据通过 UDP 发送给服务器


server程序:

左右滑动查看完整内容

45 iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr)); //将套接字与特定的 IP 地址和端口号绑定46 if (-1 == iRet)47 {48 printf("bind error!\n");49 return -1;50 }515253 while (1) //服务器将持续运行,等待客户端的消息54 {55 iAddrLen = sizeof(struct sockaddr);56 iRecvLen = recvfrom(iSocketServer, ucRecvBuf, 999, 0, (struct sockaddr*)&tSocketClientAddr, &iAddrLen);// 接收客户端发送的消息57 if (iRecvLen > 0)58 {59 ucRecvBuf[iRecvLen] = '\0';60 printf("Get Msg From %s : %s\n", inet_ntoa(tSocketClientAddr.sin_addr), ucRecvBuf);61 }62 }6364 close(iSocketServer);65 return 0;66 }


编译:

左右滑动查看完整内容

source /opt/remi-sdk/environment-setup-aarch64-poky-linux$CC netcp.c -o netcp$CC client.c -o client


假设设置开发板的IP为:192.168.5.9,上传程序到开发板上。

scp ./server root@192.168.5.9:/mnt/scp ./client root@192.168.5.9:/mnt/


测试:

进入/mnt目录运行程序:

root@myir-remi-1g:~# cd /mnt/root@myir-remi-1g:/mnt# lsserver netcp


后台运行服务程序,运行客户端程序进行文件信息传输。

左右滑动查看完整内容

root@myir-remi-1g:/mnt# ./server &root@myir-remi-1g:/mnt# ./client 127.0.0.1nihaoGet Msg From 127.0.0.1 : nihao


运行程序后,可以在终端输入信息后,可以看到服务端打印接收到的信息。


需要技术支持?

如您在使用瑞萨MCU/MPU产品中有任何问题,可识别下方二维码或复制网址到浏览器中打开,进入瑞萨技术论坛寻找答案或获取在线技术支持。

https://community-ja.renesas.com/zh/forums-groups/mcu-mpu/



未完待续


推荐阅读

在Framebuffer上显示图片 - RZ MPU工业控制教程连载(15)

网络通信概述 - RZ MPU工业控制教程连载(16)

网络编程主要函数介绍 - RZ MPU工业控制教程连载(17)

更多精彩,敬请关注


评论
  • 光伏逆变器是一种高效的能量转换设备,它能够将光伏太阳能板(PV)产生的不稳定的直流电压转换成与市电频率同步的交流电。这种转换后的电能不仅可以回馈至商用输电网络,还能供独立电网系统使用。光伏逆变器在商业光伏储能电站和家庭独立储能系统等应用领域中得到了广泛的应用。光耦合器,以其高速信号传输、出色的共模抑制比以及单向信号传输和光电隔离的特性,在光伏逆变器中扮演着至关重要的角色。它确保了系统的安全隔离、干扰的有效隔离以及通信信号的精准传输。光耦合器的使用不仅提高了系统的稳定性和安全性,而且由于其低功耗的
    晶台光耦 2024-12-02 10:40 105浏览
  • 《高速PCB设计经验规则应用实践》+PCB绘制学习与验证读书首先看目录,我感兴趣的是这一节;作者在书中列举了一条经典规则,然后进行详细分析,通过公式推导图表列举说明了传统的这一规则是受到电容加工特点影响的,在使用了MLCC陶瓷电容后这一条规则已经不再实用了。图书还列举了高速PCB设计需要的专业工具和仿真软件,当然由于篇幅所限,只是介绍了一点点设计步骤;我最感兴趣的部分还是元件布局的经验规则,在这里列举如下:在这里,演示一下,我根据书本知识进行电机驱动的布局:这也算知行合一吧。对于布局书中有一句:
    wuyu2009 2024-11-30 20:30 106浏览
  • RDDI-DAP错误通常与调试接口相关,特别是在使用CMSIS-DAP协议进行嵌入式系统开发时。以下是一些可能的原因和解决方法: 1. 硬件连接问题:     检查调试器(如ST-Link)与目标板之间的连接是否牢固。     确保所有必要的引脚都已正确连接,没有松动或短路。 2. 电源问题:     确保目标板和调试器都有足够的电源供应。     检查电源电压是否符合目标板的规格要求。 3. 固件问题: &n
    丙丁先生 2024-12-01 17:37 83浏览
  • 当前,智能汽车产业迎来重大变局,随着人工智能、5G、大数据等新一代信息技术的迅猛发展,智能网联汽车正呈现强劲发展势头。11月26日,在2024紫光展锐全球合作伙伴大会汽车电子生态论坛上,紫光展锐与上汽海外出行联合发布搭载紫光展锐A7870的上汽海外MG量产车型,并发布A7710系列UWB数字钥匙解决方案平台,可应用于数字钥匙、活体检测、脚踢雷达、自动泊车等多种智能汽车场景。 联合发布量产车型,推动汽车智能化出海紫光展锐与上汽海外出行达成战略合作,联合发布搭载紫光展锐A7870的量产车型
    紫光展锐 2024-12-03 11:38 65浏览
  • 遇到部分串口工具不支持1500000波特率,这时候就需要进行修改,本文以触觉智能RK3562开发板修改系统波特率为115200为例,介绍瑞芯微方案主板Linux修改系统串口波特率教程。温馨提示:瑞芯微方案主板/开发板串口波特率只支持115200或1500000。修改Loader打印波特率查看对应芯片的MINIALL.ini确定要修改的bin文件#查看对应芯片的MINIALL.ini cat rkbin/RKBOOT/RK3562MINIALL.ini修改uart baudrate参数修改以下目
    Industio_触觉智能 2024-12-03 11:28 41浏览
  • 作为优秀工程师的你,已身经百战、阅板无数!请先醒醒,新的项目来了,这是一个既要、又要、还要的产品需求,ARM核心板中一个处理器怎么能实现这么丰富的外围接口?踌躇之际,你偶阅此文。于是,“潘多拉”的魔盒打开了!没错,USB资源就是你打开新世界得钥匙,它能做哪些扩展呢?1.1  USB扩网口通用ARM处理器大多带两路网口,如果项目中有多路网路接口的需求,一般会选择在主板外部加交换机/路由器。当然,出于成本考虑,也可以将Switch芯片集成到ARM核心板或底板上,如KSZ9897、
    万象奥科 2024-12-03 10:24 37浏览
  • 11-29学习笔记11-29学习笔记习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-02 23:58 51浏览
  • 概述 说明(三)探讨的是比较器一般带有滞回(Hysteresis)功能,为了解决输入信号转换速率不够的问题。前文还提到,即便使能滞回(Hysteresis)功能,还是无法解决SiPM读出测试系统需要解决的问题。本文在说明(三)的基础上,继续探讨为SiPM读出测试系统寻求合适的模拟脉冲检出方案。前四代SiPM使用的高速比较器指标缺陷 由于前端模拟信号属于典型的指数脉冲,所以下降沿转换速率(Slew Rate)过慢,导致比较器检出出现不必要的问题。尽管比较器可以使能滞回(Hysteresis)模块功
    coyoo 2024-12-03 12:20 70浏览
  • 最近几年,新能源汽车愈发受到消费者的青睐,其销量也是一路走高。据中汽协公布的数据显示,2024年10月,新能源汽车产销分别完成146.3万辆和143万辆,同比分别增长48%和49.6%。而结合各家新能源车企所公布的销量数据来看,比亚迪再度夺得了销冠宝座,其10月新能源汽车销量达到了502657辆,同比增长66.53%。众所周知,比亚迪是新能源汽车领域的重要参与者,其一举一动向来为外界所关注。日前,比亚迪汽车旗下品牌方程豹汽车推出了新车方程豹豹8,该款车型一上市就迅速吸引了消费者的目光,成为SUV
    刘旷 2024-12-02 09:32 98浏览
  •         温度传感器的精度受哪些因素影响,要先看所用的温度传感器输出哪种信号,不同信号输出的温度传感器影响精度的因素也不同。        现在常用的温度传感器输出信号有以下几种:电阻信号、电流信号、电压信号、数字信号等。以输出电阻信号的温度传感器为例,还细分为正温度系数温度传感器和负温度系数温度传感器,常用的铂电阻PT100/1000温度传感器就是正温度系数,就是说随着温度的升高,输出的电阻值会增大。对于输出
    锦正茂科技 2024-12-03 11:50 66浏览
  • 戴上XR眼镜去“追龙”是种什么体验?2024年11月30日,由上海自然博物馆(上海科技馆分馆)与三湘印象联合出品、三湘印象旗下观印象艺术发展有限公司(下简称“观印象”)承制的《又见恐龙》XR嘉年华在上海自然博物馆重磅开幕。该体验项目将于12月1日正式对公众开放,持续至2025年3月30日。双向奔赴,恐龙IP撞上元宇宙不久前,上海市经济和信息化委员会等部门联合印发了《上海市超高清视听产业发展行动方案》,特别提到“支持博物馆、主题乐园等场所推动超高清视听技术应用,丰富线下文旅消费体验”。作为上海自然
    电子与消费 2024-11-30 22:03 86浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦