基于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)

更多精彩,敬请关注


评论
  • 大模型的赋能是指利用大型机器学习模型(如深度学习模型)来增强或改进各种应用和服务。这种技术在许多领域都显示出了巨大的潜力,包括但不限于以下几个方面: 1. 企业服务:大模型可以用于构建智能客服系统、知识库问答系统等,提升企业的服务质量和运营效率。 2. 教育服务:在教育领域,大模型被应用于个性化学习、智能辅导、作业批改等,帮助教师减轻工作负担,提高教学质量。 3. 工业智能化:大模型有助于解决工业领域的复杂性和不确定性问题,尽管在认知能力方面尚未完全具备专家级的复杂决策能力。 4. 消费
    丙丁先生 2025-01-07 09:25 87浏览
  • 每日可见的315MHz和433MHz遥控模块,你能分清楚吗?众所周知,一套遥控设备主要由发射部分和接收部分组成,发射器可以将控制者的控制按键经过编码,调制到射频信号上面,然后经天线发射出无线信号。而接收器是将天线接收到的无线信号进行解码,从而得到与控制按键相对应的信号,然后再去控制相应的设备工作。当前,常见的遥控设备主要分为红外遥控与无线电遥控两大类,其主要区别为所采用的载波频率及其应用场景不一致。红外遥控设备所采用的射频信号频率一般为38kHz,通常应用在电视、投影仪等设备中;而无线电遥控设备
    华普微HOPERF 2025-01-06 15:29 137浏览
  •     为控制片内设备并且查询其工作状态,MCU内部总是有一组特殊功能寄存器(SFR,Special Function Register)。    使用Eclipse环境调试MCU程序时,可以利用 Peripheral Registers Viewer来查看SFR。这个小工具是怎样知道某个型号的MCU有怎样的寄存器定义呢?它使用一种描述性的文本文件——SVD文件。这个文件存储在下面红色字体的路径下。    例:南京沁恒  &n
    电子知识打边炉 2025-01-04 20:04 100浏览
  • PLC组态方式主要有三种,每种都有其独特的特点和适用场景。下面来简单说说: 1. 硬件组态   定义:硬件组态指的是选择适合的PLC型号、I/O模块、通信模块等硬件组件,并按照实际需求进行连接和配置。    灵活性:这种方式允许用户根据项目需求自由搭配硬件组件,具有较高的灵活性。    成本:可能需要额外的硬件购买成本,适用于对系统性能和扩展性有较高要求的场合。 2. 软件组态   定义:软件组态主要是通过PLC
    丙丁先生 2025-01-06 09:23 86浏览
  • 在智能家居领域中,Wi-Fi、蓝牙、Zigbee、Thread与Z-Wave等无线通信协议是构建短距物联局域网的关键手段,它们常在实际应用中交叉运用,以满足智能家居生态系统多样化的功能需求。然而,这些协议之间并未遵循统一的互通标准,缺乏直接的互操作性,在进行组网时需要引入额外的网关作为“翻译桥梁”,极大地增加了系统的复杂性。 同时,Apple HomeKit、SamSung SmartThings、Amazon Alexa、Google Home等主流智能家居平台为了提升市占率与消费者
    华普微HOPERF 2025-01-06 17:23 151浏览
  • 本文介绍Linux系统更换开机logo方法教程,通用RK3566、RK3568、RK3588、RK3576等开发板,触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。制作图片开机logo图片制作注意事项(1)图片必须为bmp格式;(2)图片大小不能大于4MB;(3)BMP位深最大是32,建议设置为8;(4)图片名称为logo.bmp和logo_kernel.bmp;开机
    Industio_触觉智能 2025-01-06 10:43 87浏览
  • 根据Global Info Research项目团队最新调研,预计2030年全球封闭式电机产值达到1425百万美元,2024-2030年期间年复合增长率CAGR为3.4%。 封闭式电机是一种电动机,其外壳设计为密闭结构,通常用于要求较高的防护等级的应用场合。封闭式电机可以有效防止外部灰尘、水分和其他污染物进入内部,从而保护电机的内部组件,延长其使用寿命。 环洋市场咨询机构出版的调研分析报告【全球封闭式电机行业总体规模、主要厂商及IPO上市调研报告,2025-2031】研究全球封闭式电机总体规
    GIRtina 2025-01-06 11:10 109浏览
  • 彼得·德鲁克被誉为“现代管理学之父”,他的管理思想影响了无数企业和管理者。然而,关于他的书籍分类,一种流行的说法令人感到困惑:德鲁克一生写了39本书,其中15本是关于管理的,而其中“专门写工商企业或为企业管理者写的”只有两本——《为成果而管理》和《创新与企业家精神》。这样的表述广为流传,但深入探讨后却发现并不完全准确。让我们一起重新审视这一说法,解析其中的矛盾与根源,进而重新认识德鲁克的管理思想及其著作的真正价值。从《创新与企业家精神》看德鲁克的视角《创新与企业家精神》通常被认为是一本专为企业管
    优思学院 2025-01-06 12:03 134浏览
  • 这篇内容主要讨论三个基本问题,硅电容是什么,为什么要使用硅电容,如何正确使用硅电容?1.  硅电容是什么首先我们需要了解电容是什么?物理学上电容的概念指的是给定电位差下自由电荷的储藏量,记为C,单位是F,指的是容纳电荷的能力,C=εS/d=ε0εrS/4πkd(真空)=Q/U。百度百科上电容器的概念指的是两个相互靠近的导体,中间夹一层不导电的绝缘介质。通过观察电容本身的定义公式中可以看到,在各个变量中比较能够改变的就是εr,S和d,也就是介质的介电常数,金属板有效相对面积以及距离。当前
    知白 2025-01-06 12:04 180浏览
  • By Toradex 秦海1). 简介嵌入式平台设备基于Yocto Linux 在开发后期量产前期,为了安全以及提高启动速度等考虑,希望将 ARM 处理器平台的 Debug Console 输出关闭,本文就基于 NXP i.MX8MP ARM 处理器平台来演示相关流程。 本文所示例的平台来自于 Toradex Verdin i.MX8MP 嵌入式平台。  2. 准备a). Verdin i.MX8MP ARM核心版配合Dahlia载板并
    hai.qin_651820742 2025-01-07 14:52 58浏览
  • 村田是目前全球量产硅电容的领先企业,其在2016年收购了法国IPDiA头部硅电容器公司,并于2023年6月宣布投资约100亿日元将硅电容产能提升两倍。以下内容主要来自村田官网信息整理,村田高密度硅电容器采用半导体MOS工艺开发,并使用3D结构来大幅增加电极表面,因此在给定的占位面积内增加了静电容量。村田的硅技术以嵌入非结晶基板的单片结构为基础(单层MIM和多层MIM—MIM是指金属 / 绝缘体/ 金属) 村田硅电容采用先进3D拓扑结构在100um内,使开发的有效静电容量面积相当于80个
    知白 2025-01-07 15:02 87浏览
  • 随着市场需求不断的变化,各行各业对CPU的要求越来越高,特别是近几年流行的 AIOT,为了有更好的用户体验,CPU的算力就要求更高了。今天为大家推荐由米尔基于瑞芯微RK3576处理器推出的MYC-LR3576核心板及开发板。关于RK3576处理器国产CPU,是这些年的骄傲,华为手机全国产化,国人一片呼声,再也不用卡脖子了。RK3576处理器,就是一款由国产是厂商瑞芯微,今年第二季推出的全新通用型的高性能SOC芯片,这款CPU到底有多么的高性能,下面看看它的几个特性:8核心6 TOPS超强算力双千
    米尔电子嵌入式 2025-01-03 17:04 55浏览
  • 根据环洋市场咨询(Global Info Research)项目团队最新调研,预计2030年全球无人机锂电池产值达到2457百万美元,2024-2030年期间年复合增长率CAGR为9.6%。 无人机锂电池是无人机动力系统中存储并释放能量的部分。无人机使用的动力电池,大多数是锂聚合物电池,相较其他电池,锂聚合物电池具有较高的能量密度,较长寿命,同时也具有良好的放电特性和安全性。 全球无人机锂电池核心厂商有宁德新能源科技、欣旺达、鹏辉能源、深圳格瑞普和EaglePicher等,前五大厂商占有全球
    GIRtina 2025-01-07 11:02 81浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦