電子產(chǎn)業(yè)一站式賦能平臺

PCB聯(lián)盟網(wǎng)

搜索
查看: 24|回復: 0
收起左側

基于TCP實現(xiàn)文件傳輸與UDP編程方法

[復制鏈接]

265

主題

265

帖子

1448

積分

三級會員

Rank: 3Rank: 3

積分
1448
跳轉到指定樓層
樓主
發(fā)表于 昨天 11:45 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
關注+星標公眾,不錯過精彩內(nèi)容

直接來源 | 瑞薩嵌入式小百科
TCP/IP通信協(xié)議我們做項目編程的時候,經(jīng)常都會用到,它的底層原理其實有點復雜,但我們實際編程應用的時候,主要都是調用一些接口,了解了這些接口的原理,實現(xiàn)起來也不是很難。
今天就結合源碼講講基于TCP實現(xiàn)文件傳輸與UDP編程方法。
基于TCP協(xié)議,實現(xiàn)文件傳輸。約定規(guī)則:先傳輸一個結構體,里面含有“文件名,文件大小”
1
Client:
  • open文件,得到文件狀態(tài)(大。瑯嬙旖Y構體,發(fā)送結構體。
  • 循環(huán)read文件,發(fā)送網(wǎng)絡數(shù)據(jù)。
    [/ol]
    2
    Server:
  • 讀網(wǎng)絡數(shù)據(jù),得到結構體,創(chuàng)建文件。
  • 循環(huán)read網(wǎng)絡數(shù)據(jù),寫文件,數(shù)量足夠就關閉文件。
    [/ol]
    獲取文件信息

    本節(jié)源碼位于如下目錄:


    關鍵代碼:
    左右滑動查看完整內(nèi)容
  • /* ./file_stat 1.txt */int main(int argc, char **argv){ struct stat statbuf; if (argc != 2) { printf("Usage: %s
    ", argv[0]); return -1; } /* 1. open */ int fd = open(argv[1], O_RDONLY); if (-1 == fd) { printf("can't open %s
    ", argv[1]); return -1; } /* 2. fstat */ if (fstat(fd, &statbuf) == -1) { printf("can't get stat of %s
    ", argv[1]); return -1; }           /* 3. printf */        printf("file size = %d
    ", statbuf.st_size);         return 0;        }
    實驗方法:
  • gcc -o file_stat file_stat.cecho 123 > 1.txt./file_stat 1.txt

    本地讀文件、寫文件

    本節(jié)源碼位于如下目錄:


    關鍵代碼:
    左右滑動查看完整內(nèi)容
  • /* 4. 創(chuàng)建目標文件 */ int fd2 = open(argv[2], O_CREAT|O_WRONLY|O_TRUNC); if (-1 == fd2) { printf("can't create %s
    ", argv[2]); return -1; }  while (1) { /* 讀原文件 */ unsigned char c; if (read(fd, &c, 1) != 1) break; /* 寫目標文件 */ if (write(fd2, &c, 1) != 1) break; }
    上機實驗:
    左右滑動查看完整內(nèi)容
  • 編譯程序: gcc -o mycp mycp.c生成大的測試文件:dd if=/dev/zero of=tmp.txt bs=1024 count=10240測試:date ; ./mycp tmp.txt tmp6.txt ; date
    實現(xiàn)網(wǎng)絡傳輸:傳輸文件信息

    本節(jié)源碼位于如下目錄:
  • 06_源碼\8.4.2_本地讀文件、寫文件


    源碼為“netcp1_info”

    netcp程序:
    左右滑動查看完整內(nèi)容
  • 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:
    ");40 printf("%s   
    ", argv[0]);41 return -1;42 }4344 iSocketClient = socket(AF_INET, SOCK_STREAM, 0);// 創(chuàng)建一個套接字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
    ");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!
    ");61 return -1;62 }6364 /* 獲得文件信息 */65 struct stat statbuf;6667 int fd = open(argv[1], O_RDONLY);// 打開第一個參數(shù)指定的本地文件68 if (-1 == fd)69 {70 printf("can't open %s
    ", argv[1]);71 return -1;72 }7374 if (fstat(fd, &statbuf) == -1)// 獲取文件信息(大。75 {76 printf("can't get stat of %s
    ", argv[1]);77 return -1;78 }7980 /* 發(fā)送文件信息 */81 struct netcp_info info;82 info.len = statbuf.st_size;83 strcpy(info.name, argv[3]);84 //將 info 結構發(fā)送到服務器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
    ", iSendLen, sizeof(info));94 }959697 return 0;98 }
    server程序:
    左右滑動查看完整內(nèi)容
  • 43 signal(SIGCHLD,SIG_IGN);// 忽略子進程結束信號,防止出現(xiàn)僵尸進程。4445 iSocketServer = socket(AF_INET, SOCK_STREAM, 0);//創(chuàng)建一個 IPv4 的 TCP 套接字46 if (-1 == iSocketServer)47 {48 printf("socket error!
    ");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!
    ");61 return -1;62 }6364 iRet = listen(iSocketServer, BACKLOG);// 函數(shù)使服務器的套接字進入監(jiān)聽狀態(tài)65 if (-1 == iRet)66 {67 printf("listen error!
    ");68 return -1;69 }7071 while (1) //服務器將持續(xù)運行,等待客戶端的連接請求72 {73 iAddrLen = sizeof(struct sockaddr);74 iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);// 等待客戶端的連接請求,并創(chuàng)建一個新的套接字用于與客戶端通信75 if (-1 != iSocketClient)76 {77 iClientNum++;78 printf("Get connect from client %d : %s
    ", iClientNum, inet_ntoa(tSocketClientAddr.sin_addr));79 if (!fork())//創(chuàng)建子進程來處理客戶端請求,父進程繼續(xù)監(jiān)聽其他客戶端的連接請求80 {81 /* 讀 100 字節(jié)的文件信息 */82 struct netcp_info info;83 //收客戶端發(fā)送的文件信息,包括文件長度和文件名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
    ", iClientNum, info.len, info.name);93 }9495 }96 }97 }
    編譯:
    左右滑動查看完整內(nèi)容
  • source /opt/remi-sdk/environment-setup-aarch64-poky-linux$CC netcp.c -o netcp$CC server.c -o server
    假設設置開發(fā)板的IP為:192.168.5.9,上傳程序到開發(fā)板上。
  • 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
    在運行程序前,請先創(chuàng)建txt文件,寫入任意數(shù)據(jù)至文件中,用于后續(xù)文件傳輸。
    左右滑動查看完整內(nèi)容
  • root@myir-remi-1g:/mnt# touch 1.txtroot@myir-remi-1g:/mnt# echo 123 > 1.txt
    后臺運行服務程序,運行客戶端程序進行文件信息傳輸。
    左右滑動查看完整內(nèi)容
  • 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
    運行程序后,可以看到終端輸出文件信息內(nèi)容。

    注意:如果修改server.c,再次編譯、運行前,先關閉之前的sever程序。命令為:killall server。

    實現(xiàn)網(wǎng)絡傳輸:傳輸文件數(shù)據(jù)

    本節(jié)源碼位于如下目錄:


    源碼為“netcp2_info”

    netcp程序:
    左右滑動查看完整內(nèi)容
  • 80 /* 發(fā)送文件信息 */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);//發(fā)送文件信息86 if (iSendLen 0)87 {88 close(iSocketClient);89 return -1;90 }91 else92 {93 printf("send %d datas, %ld
    ", iSendLen, sizeof(info));94 }9596 /* 傳輸數(shù)據(jù) */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 /* 通過網(wǎng)絡發(fā)送給服務器 */112 iSendLen = send(iSocketClient, buf, len, 0);113 if (iSendLen != len)114 {115 close(iSocketClient);116 return -1;117 }118 //printf("send ok %d
    ", iSendLen);119120 }121 }122 return 0;123 }
    server程序:
    左右滑動查看完整內(nèi)容
  • 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
    ", iClientNum, inet_ntoa(tSocketClientAddr.sin_addr));80 if (!fork())81 {82 /* 讀 100 字節(jié)的文件信息 */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
    ", iClientNum, info.len, info.name);94 }9596 /* 創(chuàng)建文件 */97 int fd = open(info.name, O_CREAT|O_WRONLY|O_TRUNC, 0666);98 if (-1 == fd)99 {100 printf("can't create %s
    ", info.name);101 return -1;102 }103 /* 接收網(wǎng)絡數(shù)據(jù),寫文件 */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
    ");120 return -1;121 }122 writelen += iRecvLen;123 if (writelen == info.len)124 {125 /* 接收到所有數(shù)據(jù)并且成功寫入 */126 printf("get file %s ok
    ", info.name);127 close(fd);128 return 0;129 }
    編譯:
    左右滑動查看完整內(nèi)容
  • source /opt/remi-sdk/environment-setup-aarch64-poky-linux$CC netcp.c -o netcp$CC server.c -o server
    假設設置開發(fā)板的IP為:192.168.5.9,上傳程序到開發(fā)板上。

    測試:
    進入/mnt目錄運行程序:
  • root@myir-remi-1g:~# cd /mnt/root@myir-remi-1g:/mnt# lsserver netcp
    在運行程序前,請先創(chuàng)建txt文件,寫入任意數(shù)據(jù)至文件中,用于后續(xù)文件傳輸。
    左右滑動查看完整內(nèi)容
  • root@myir-remi-1g:/mnt# touch 1.txtroot@myir-remi-1g:/mnt# echo 123 > 1.txt
    后臺運行服務程序,運行客戶端程序進行文件信息傳輸。
    左右滑動查看完整內(nèi)容
  • 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
    運行程序后,可以看到終端輸出文件數(shù)據(jù)獲取成功。

    注意:如果修改server.c,再次編譯、運行前,先關閉之前的sever程序。命令為:killall server。


    UDP編程示例
    本節(jié)源碼位于如下目錄:


    Client程序:
    左右滑動查看完整內(nèi)容
  • 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
    ");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!
    ");51 return -1;52 }53 #endif5455 while (1)56 {57 if (fgets(ucSendBuf, 999, stdin)) //從標準輸入讀取用戶輸入的數(shù)據(jù)。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);// 將數(shù)據(jù)通過 UDP 發(fā)送給服務器
    server程序:
    左右滑動查看完整內(nèi)容
  • 45 iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr)); //將套接字與特定的 IP 地址和端口號綁定46 if (-1 == iRet)47 {48 printf("bind error!
    ");49 return -1;50 }515253 while (1) //服務器將持續(xù)運行,等待客戶端的消息54 {55 iAddrLen = sizeof(struct sockaddr);56 iRecvLen = recvfrom(iSocketServer, ucRecvBuf, 999, 0, (struct sockaddr*)&tSocketClientAddr, &iAddrLen);// 接收客戶端發(fā)送的消息57 if (iRecvLen > 0)58 {59 ucRecvBuf[iRecvLen] = '\0';60 printf("Get Msg From %s : %s
    ", inet_ntoa(tSocketClientAddr.sin_addr), ucRecvBuf);61 }62 }6364 close(iSocketServer);65 return 0;66 }
    編譯:
    左右滑動查看完整內(nèi)容
  • source /opt/remi-sdk/environment-setup-aarch64-poky-linux$CC netcp.c -o netcp$CC client.c -o client
    假設設置開發(fā)板的IP為:192.168.5.9,上傳程序到開發(fā)板上。
  • 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
    后臺運行服務程序,運行客戶端程序進行文件信息傳輸。
    左右滑動查看完整內(nèi)容
  • root@myir-remi-1g:/mnt# ./server &root@myir-remi-1g:/mnt# ./client 127.0.0.1nihaoGet Msg From 127.0.0.1 : nihao
    運行程序后,可以在終端輸入信息后,可以看到服務端打印接收到的信息。

    ------------ END ------------

    ●瑞薩RA8系列教程 | 初識瑞薩 RA8 系列單片機●瑞薩RA8系列教程 | 瑞薩 RA8 開發(fā)環(huán)境搭建●瑞薩RA8系列教程 | 基于 Keil 開發(fā) RA8單片機瑞薩RA8系列教程 | 基于e2s實現(xiàn)RA8串口輸出配置
  • 回復

    使用道具 舉報

    發(fā)表回復

    您需要登錄后才可以回帖 登錄 | 立即注冊

    本版積分規(guī)則


    聯(lián)系客服 關注微信 下載APP 返回頂部 返回列表