交流群:
往期課程:(往期視頻可進群獲取)
tips:第2課內容稍有調整,最終請以RT-文檔中心發布為準
(文末有禮)
第6課教程視頻
1 背景介紹
編程一般采用客戶端-服務器模式,即由客戶進程向服務器進程發出請求視頻 服務器運行失敗,服務器進程執行請求的任務并將執行結果返回給客戶進程的模式。
本教程介紹了如何編寫一個基于 編程實現的 TCP 客戶端。我們先將 編程的流程列出來,然后給出具體的實例。
TCP 客戶端的 編程流程
創建
建立連接
通信
關閉
如下圖所示:
2 準備工作
2.1 獲取示例代碼
RT- 軟件包中已有一份該示例代碼 .c(鏈接:)視頻 服務器運行失敗,可以通過 env 配置將示例代碼加入到項目中。
RT-Thread online packages ?--->
? ? miscellaneous packages ?--->
? ? ? ? samples: RT-Thread kernel and components samples ?--->
? ? ? ? ? ? [*] a network_samples package for rt-thread ?--->
? ? ? ? ? ? ? ? [*] [network] tcp client
2.2 示例代碼文件
/*
* 程序清單:tcp 客戶端
*
* 這是一個 tcp 客戶端的例程
* 導出 tcpclient 命令到控制終端
* 命令調用格式:tcpclient URL PORT
* URL:服務器地址 PORT::端口號
* 程序功能:接收并顯示從服務端發送過來的信息,接收到開頭是 'q' 或 'Q' 的信息退出程序
*/
#include
#include /* 使用BSD socket,需要包含socket.h頭文件 */
#include "netdb.h"
#define BUFSZ ? 1024
static const char send_data[] = "This is TCP Client from RT-Thread."; /* 發送用到的數據 */
void tcpclient(int argc, char **argv)
{
? ?int ret;
? ?char *recv_data;
? ?struct hostent *host;
? ?int sock, bytes_received;
? ?struct sockaddr_in server_addr;
? ?const char *url;
? ?int port;
? ?if (argc < 3)
? ?{
? ? ? ?rt_kprintf("Usage: tcpclient URL PORT\n");
? ? ? ?rt_kprintf("Like: tcpclient 192.168.12.44 5000\n");
? ? ? ?return ;
? ?}
? ?url = argv[1];
? ?port = strtoul(argv[2], 0, 10);
? ?/* 通過函數入口參數url獲得host地址(如果是域名,會做域名解析) */
? ?host = gethostbyname(url);
? ?/* 分配用于存放接收數據的緩沖 */
? ?recv_data = rt_malloc(BUFSZ);
? ?if (recv_data == RT_NULL)
? ?{
? ? ? ?rt_kprintf("No memory\n");
? ? ? ?return;
? ?}
? ?/* 創建一個socket,類型是SOCKET_STREAM,TCP類型 */
? ?if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
? ?{
? ? ? ?/* 創建socket失敗 */
? ? ? ?rt_kprintf("Socket error\n");
? ? ? ?/* 釋放接收緩沖 */
? ? ? ?rt_free(recv_data);
? ? ? ?return;
? ?}
? ?/* 初始化預連接的服務端地址 */
? ?server_addr.sin_family = AF_INET;
? ?server_addr.sin_port = htons(port);
? ?server_addr.sin_addr = *((struct in_addr *)host->h_addr);
? ?rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
? ?/* 連接到服務端 */
? ?if (connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
? ?{
? ? ? ?/* 連接失敗 */
? ? ? ?rt_kprintf("Connect fail!\n");
? ? ? ?closesocket(sock);
? ? ? ?/*釋放接收緩沖 */
? ? ? ?rt_free(recv_data);
? ? ? ?return;
? ?}
? ?while (1)
? ?{
? ? ? ?/* 從sock連接中接收最大BUFSZ - 1字節數據 */
? ? ? ?bytes_received = recv(sock, recv_data, BUFSZ - 1, 0);
? ? ? ?if (bytes_received < 0)
? ? ? ?{
? ? ? ? ? ?/* 接收失敗,關閉這個連接 */
? ? ? ? ? ?closesocket(sock);
? ? ? ? ? ?rt_kprintf("\nreceived error,close the socket.\r\n");
? ? ? ? ? ?/* 釋放接收緩沖 */
? ? ? ? ? ?rt_free(recv_data);
? ? ? ? ? ?break;
? ? ? ?}
? ? ? ?else if (bytes_received == 0)
? ? ? ?{
? ? ? ? ? ?/* 默認 recv 為阻塞模式,此時收到0認為連接出錯,關閉這個連接 */
? ? ? ? ? ?closesocket(sock);
? ? ? ? ? ?rt_kprintf("\nreceived error,close the socket.\r\n");
? ? ? ? ? ?/* 釋放接收緩沖 */
? ? ? ? ? ?rt_free(recv_data);
? ? ? ? ? ?break;
? ? ? ?}
? ? ? ?/* 有接收到數據,把末端清零 */
? ? ? ?recv_data[bytes_received] = '\0';
? ? ? ?if (strncmp(recv_data, "q", 1) == 0 || strncmp(recv_data, "Q", 1) == 0)
? ? ? ?{
? ? ? ? ? /* 如果是首字母是q或Q,關閉這個連接 */
? ? ? ? ? closesocket(sock);
? ? ? ? ? rt_kprintf("\n got a 'q' or 'Q',close the socket.\r\n");
? ? ? ? ? ?/* 釋放接收緩沖 */
? ? ? ? ? ?rt_free(recv_data);
? ? ? ? ? ?break;
? ? ? ?}
? ? ? ?else
? ? ? ?{
? ? ? ? ? ?/* 在控制終端顯示收到的數據 */
? ? ? ? ? ?rt_kprintf("\nReceived data = %s ", recv_data);
? ? ? ?}
? ? ? ?/* 發送數據到sock連接 */
? ? ? ?ret = send(sock, send_data, strlen(send_data), 0);
? ? ? ?if (ret < 0)
? ? ? ?{
? ? ? ? ? ?/* 接收失敗,關閉這個連接 */
? ? ? ? ? ?closesocket(sock);
? ? ? ? ? ?rt_kprintf("\nsend error,close the socket.\r\n");
? ? ? ? ? ?rt_free(recv_data);
? ? ? ? ? ?break;
? ? ? ?}
? ? ? ?else if (ret == 0)
? ? ? ?{
? ? ? ? ? /* 打印send函數返回值為0的警告信息 */
? ? ? ? ? rt_kprintf("\n Send warning,send function return 0.\r\n");
? ? ? }
? }
? return;
}
MSH_CMD_EXPORT(tcpclient, a tcp client sample);
3 在 msh shell 中運行示例代碼
在運行示例代碼之前需要先在電腦上開啟一個 TCP 服務器,這里以網絡調試助手 IPOP 為例。
然后,查看本機 ip 地址
在 系統中打開命令提示符,輸入 即可查看本機 ip
然后,在系統運行起來后,在 msh 命令行下輸入下面的命令即可讓示例代碼運行。
msh> tcpclient 192.168.12.44 5000
有兩個參數 URL PORT,其中:
4 預期結果
可以看出客戶端已經連接到服務器了。然后,從服務端向客戶端發送數據
從客戶端能接收到服務端發來的數據,發送字符 'q' 即可斷開連接
5 注意事項6 引用參考 (以下鏈接請復制至外部瀏覽器打開)
近期活動
1.RT- 2018開發者大會 南京站:1、你將有機會與RT- 團隊直接交流探討 2、看到來自RTT的合作伙伴或社區開發者的最新產品、作品 3、親身參與到RT-的動手實操,學習和體驗一個IoT應用作品的誕生 4、還有多款開發板抽獎噢~
我是彩蛋
福利來了!在留言區留言被精選且點贊數前3名的小伙伴將獲得我們的11.7南京開發者大會套件——數字變換時鐘開發套件
作品圖
PS:
活動時間:2018.11.09-2018.11.11 00:00