野火F429+RT-Thread TCP客户端实验学习笔记

野火F429-挑战者_V2开发板+RT-Thread 学习TCP客户端socket编程实验,代码实现功能:实现一个TCP客户端程序,接收并显示从服务端发送过来的信息,并且返回给服务器端。接收到开头是 'q' 或 'Q' 的信息退出程序。支持服务器离线重启之后自动重连、支持客户端断网重连功能。

程序执行方法:通过FinSH 控制台 执行命令的方法运行TCP客户端程序,命令调用格式:tcpclient URL PORT,例如  tcpclient  192.168.1.100  5000。

代码运行结果截图如下

详情软件代码如下:

/*
 * 程序清单:tcp 客户端
 *
 * 这是一个 tcp 客户端的例程
 * 导出 tcpclient 命令到控制终端
 * 命令调用格式:tcpclient URL PORT
 * URL:服务器地址 PORT::端口号
 * 程序功能:接收并显示从服务端发送过来的信息,接收到开头是 'q' 或 'Q' 的信息退出程序
*/
#include <rtthread.h>
#include <sys/socket.h> /* 使用BSD socket,需要包含socket.h头文件 */
#include <netdb.h>
#include <string.h>
#include <finsh.h>

#define BUFSZ   512

static int s_argc;
static char **s_argv;

static void tcpclient_thread(void *arg);


static void tcpclient(int argc, char **argv)
{
    rt_thread_t tid;

    s_argc = argc;
    s_argv = argv;

    //通过创建线程的方法运行tcp客户端程序,防止直接在FinSH运行导致FinSH无法处理其他事情
    rt_kprintf("tcp_client create success\n");
    tid=rt_thread_create("tcp_client",tcpclient_thread,NULL,2048,8,10);
    rt_thread_startup(tid);

}

static void tcpclient_thread(void *arg)
{
    int ret;
    char *recv_data;
    struct hostent *host;
    int sock, bytes_received;
    struct sockaddr_in server_addr;
    const char *url;
    int port;

    if (s_argc < 3)
    {
        rt_kprintf("Usage: tcpclient URL PORT\n");
        rt_kprintf("Like: tcpclient 192.168.12.44 5000\n");
        return ;
    }

    url = s_argv[1];
    port = strtoul(s_argv[2], 0, 10);

    /* 通过函数入口参数url获得host地址(如果是域名,会做域名解析) */
    host = gethostbyname(url);


    while (1)
    {

        /* 分配用于存放接收数据的缓冲 */
        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);
            rt_thread_mdelay(256);
            continue;     //跳过循环体的后面内容重新开启新的循环
        }

        /* 初始化预连接的服务端地址 */
        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);
            continue;     //跳过循环体的后面内容重新开启新的循环
        }
        else
        {
            /* 连接成功 */
            rt_kprintf("connect to server (%s , %d) successful\n",
                       inet_ntoa(server_addr.sin_addr), ntohs(server_addr.sin_port));
        }

        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);
                return;
            }
            else
            {
                /* 在控制终端显示收到的数据 */
                rt_kprintf("\nReceived data = %s ", recv_data);
            }

            /* 发送数据到sock连接 */
            ret = send(sock, recv_data, bytes_received, 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");
            }
        }
    }
    rt_kprintf("\n tcpclient thread exit\r\n");
    return;
}



MSH_CMD_EXPORT(tcpclient, a tcp client sample);

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值