设为首页 加入收藏

TOP

onps栈使用说明(3)——tcp、udp通讯测试(一)
2023-07-23 13:31:21 】 浏览:134
Tags:onps tcp udp 通讯测

4. tcp客户端

       在协议栈源码工程下,存在一个用vs2015建立的TcpServerForStackTesting工程。其运行在windows平台下,模拟实际应用场景下的tcp服务器。当tcp客户端连接到服务器后,服务器会立即下发一个1100多字节长度的控制报文到客户端。之后在整个tcp链路存续期间,服务器会每隔一段随机的时间(90秒到120秒之间)下发控制报文到客户端,模拟实际应用场景下服务器主动下发指令、数据到客户端的情形。客户端则连续上发数据报文到服务器,服务器回馈一个应答报文给客户端。客户端如果收不到该应答报文则会立即重发,直至收到应答报文或超过重试次数后重连服务器。总之,整个测试场景的设计目标就是完全契合常见的商业应用需求,以此来验证协议栈的核心功能指标是否完全达标。用vs2015打开这个工程,配置管理器指定目标平台为x64。main.cpp文件的头部定义了服务器的端口号以及报文长度等信息:

#define SRV_PORT         6410 //* 服务器端口
#define LISTEN_NUM       10   //* 最大监听数
#define RCV_BUF_SIZE     2048 //* 接收缓冲区容量
#define PKT_DATA_LEN_MAX 1200 //* 报文携带的数据最大长度,凡是超过这个长度的报文都将被丢弃

我们可以依据实际情形调整上述配置并利用这个模拟服务器测试tcp客户端的通讯功能。

……
#include "onps.h"

#define PKT_FLAG 0xEE //* 通讯报文的头部和尾部标志
typedef struct _ST_COMMUPKT_HDR_ { //* 数据及控制指令报文头部结构
    CHAR bFlag;         //* 报文头部标志,其值参看PKT_FLAG宏
    CHAR bCmd;          //* 指令,0为数据报文,1为控制指令报文
    CHAR bLinkIdx;      //* tcp链路标识,当存在多个tcp链路时,该字段用于标识这是哪一个链路
    UINT unSeqNum;      //* 报文序号
    UINT unTimestamp;   //* 报文被发送时刻的unix时间戳
    USHORT usDataLen;   //* 携带的数据长度
    USHORT usChechsum;  //* 校验和(crc16),覆盖除头部和尾部标志字符串之外的所有字段
} PACKED ST_COMMUPKT_HDR, *PST_COMMUPKT_HDR; 

typedef struct _ST_COMMUPKT_ACK_ { //* 数据即控制指令应答报文结构
    ST_COMMUPKT_HDR stHdr; //* 报文头
    UINT unTimestamp;      //* unix时间戳,其值为被应答报文携带的时间戳
    CHAR bLinkIdx;         //* tcp链路标识,其值为被应答报文携带的链路标识
    CHAR bTail;            //* 报文尾部标志,其值参看PKT_FLAG宏
} PACKED ST_COMMUPKT_ACK, *PST_COMMUPKT_ACK;

//* 提前申请一块静态存储时期的缓冲区用于tcp客户端的接收和发送,因为接收和发送的报文都比较大,所以不使用动态申请的方式
#define RCV_BUF_SIZE     1300           //* 接收缓冲区容量
#define PKT_DATA_LEN_MAX 1200           //* 报文携带的数据最大长度,凡是超过这个长度的报文都将被丢弃
static UCHAR l_ubaRcvBuf[RCV_BUF_SIZE]; //* 接收缓冲区
static UCHAR l_ubaSndBuf[sizeof(ST_COMMUPKT_HDR) + PKT_DATA_LEN_MAX]; //* 发送缓冲区,ST_COMMUPKT_HDR为通讯报文头部结构体
int main(void)
{
    EN_ONPSERR enErr; 
    SOCKET hSocket = INVALID_SOCKET;
    
    if(open_npstack_load(&enErr))
    {    
        printf("The open source network protocol stack (ver %s) is loaded successfully. \r\n", ONPS_VER);
        
        //* 协议栈加载成功,在这里初始化ethernet网卡或等待ppp链路就绪
    #if 0
        emac_init(); //* ethernet网卡初始化函数,并注册网卡到协议栈
    #else
        while(!netif_is_ready("ppp0")) //* 等待ppp链路建立成功
            os_sleep_secs(1); 
    #endif
    }
    else
    {
        printf("The open source network protocol stack failed to load, %s\r\n", onps_error(enErr));
        return -1; 
    }
    
    //* 分配一个socket         
    if(INVALID_SOCKET == (hSocket = socket(AF_INET, SOCK_STREAM, 0, &enErr))) 
    {
        //* 返回了一个无效的socket,打印错误日志
        printf("<1>socket() failed, %s\r\n", onps_error(enErr)); 
        return -1; 
    }
    
    //* 连接成功则connect()函数返回0,非0值则连接失败
    if(connect(hSocket, "192.168.0.2", 6410, 10))
    {
        printf("connect 192.168.0.2:6410 failed, %s\r\n", onps_get_last_error(hSocket, NULL));
        close(hSocket);
        return -1; 
    }
    
    //* 等待接收服务器应答或控制报文的时长(即recv()函数的等待时长),单位:秒。0不等待;大于0等待指定秒数;-1一直
    //* 等待直至数据到达或报错。设置成功返回TRUE,否则返回FALSE。这里我们设置recv()函数不等待
    //* 注意,只有连接成功后才可设置这个接收等待时长,在这里我们设置接收不等待,recv()函数立即返回,非阻塞型
    if(!socket_set_rcv_timeout(hSocket, 0, &enErr))
        printf("socket_set_rcv_timeout() failed, %s\r\n", onps_error(enErr));
    
    INT nThIdx = 0;
    while(TRUE && nThIdx < 1000)
    {
        //* 接收,前面已经设置recv()函数不等待,有数据则读取数据后立即返回,无数据则立即返回
        INT nRcvBytes = recv(hSocket, ubaRcvBuf, sizeof(ubaRcvBuf));
        if(nRcvBytes > 0)
        {
            //* 收到报文,处理之,报文有两种:一种是应答报文;另一种是服务器主动下发的控制报文
            //* 在这里添加你的自定义代码
            ……
        }
        
        //* 发送数据报文
首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇STM32F7xx外设驱动2-delay(寄存.. 下一篇STM32F7xx外设驱动7-dac(寄存器)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目