ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

W5500开发笔记 | 02 - 使用W5500 Socket API 建立TCP服务端、TCP客户端

2021-05-16 17:01:30  阅读:215  来源: 互联网

标签:02 W5500 TCP dest ret sn printf recv size


系列文章

一、实现思路

W5500内部是硬件TCP/IP协议栈,对外(MCU)只是提供了操作socket的能力,内部支持8个独立的socket,每一个socket通过Socket n寄存器区控制(0≤n≤7)

所以在编写基于Socket的网络应用程序时,可以按照查询Socket状态寄存器实现一个状态机的思路来实现

W5500驱动库中提供了Socket状态寄存器的读取宏:

/**
 * @ingroup Socket_register_access_function
 * @brief Get @ref Sn_SR register
 * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
 * @return uint8_t. Value of @ref Sn_SR.
 */
#define getSn_SR(sn) \
		WIZCHIP_READ(Sn_SR(sn))

W5500驱动库对读取出的状态值也提供了宏定义:

/* Sn_SR values */
#define SOCK_CLOSED                  0x00
#define SOCK_INIT                    0x13
#define SOCK_LISTEN                  0x14
#define SOCK_SYNSENT                 0x15	//Socket n状态改变时的临时状态,已经发送连接请求到对方
#define SOCK_SYNRECV                 0x16	//Socket n状态改变时的临时状态,成功接收到了连接请求包
#define SOCK_ESTABLISHED             0x17	
#define SOCK_FIN_WAIT                0x18	//Socket n状态改变时的临时状态,socket正在关闭
#define SOCK_CLOSING                 0x1A	//Socket n状态改变时的临时状态,socket正在关闭
#define SOCK_TIME_WAIT               0x1B	//Socket n状态改变时的临时状态,socket正在关闭
#define SOCK_CLOSE_WAIT              0x1C
#define SOCK_LAST_ACK                0x1D	//Socket n状态改变时的临时状态,socket在被动关闭状态下,正在等待对断开连接请求做出回应

二、TCP 服务端的实现

1. 实现功能

实现一个TCP服务端,可以接收TCP客户端的请求,在收到客户端数据之后打印,并回发收到的数据。

2. TCP服务端状态机

3. 实现代码

编写demo文件tcp_server.c

#include "socket.h"
#include <stdio.h>

#define DATA_BUF_SIZE			2048
static uint8_t recv_buf[DATA_BUF_SIZE];

int tcp_server(uint8_t sn, uint16_t port)
{
    int8_t ret;
    uint8_t dest_ip[4];
    uint16_t dest_port;
    uint16_t size = 0;
    
    switch (getSn_SR(sn)) {
    
        case SOCK_CLOSED:
            /* open socket */
            printf("TCP server start\r\n");
            if ((ret = socket(sn, Sn_MR_TCP, port, 0x00)) != sn) {
                printf("socket %d open fail\r\n", sn);
                return ret;
            }
            printf("socket %d open success\r\n", sn);
            break;
        
        case SOCK_INIT:
            /* waiting for a client to connect */
            printf("listen %d port...\r\n", port);
            if ((ret = listen(sn)) != SOCK_OK) {
                printf("%d:listen fail\r\n", sn);
                return ret;
            }
            printf("%d:listen success\r\n", sn);
            break;
        case SOCK_ESTABLISHED:
            /* socket has been established */
            if(getSn_IR(sn) & Sn_IR_CON) {
                getSn_DIPR(sn, dest_ip);
                dest_port = getSn_DPORT(sn);
                printf("%d:a client connect success, %d.%d.%d.%d:%d\r\n", sn, dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3], dest_port);
                
                setSn_IR(sn,Sn_IR_CON);
            }
            
            // get the size of recv data in recv buffer
            if ((size = getSn_RX_RSR(sn)) > 0) {
                if (size > DATA_BUF_SIZE) {
                    size = DATA_BUF_SIZE;
                }
                
                //recv data
                ret = recv(sn, recv_buf, DATA_BUF_SIZE);     
                if (ret <= 0) {
                    printf("%d:recv fail\r\n", sn);
                    return ret;
                } else {
                    // The actual received size
                    size = (uint16_t)ret;
                    printf("%d:recv size:%d\r\n", sn, size);
                    recv_buf[size] = '\0';
                    printf("%d:recv data:[%s]\r\n", sn, recv_buf);
                }
                
                //send resp data
                ret = send(sn, recv_buf, size);
                if (ret <= 0) {
                    printf("%d:send fail\r\n", sn);
                    
                    //close the socket
                    close(sn);
       
                    return ret;
                } else {
                    // The actual sent size
                    size = (uint16_t)ret;
                    printf("%d:send size:%d\r\n", sn, size);
                    recv_buf[size] = '\0';
                    printf("%d:send data:[%s]\r\n", sn, recv_buf);
                }   
            }
            break;
            
        case SOCK_CLOSE_WAIT:
            /* closing the socket */
            if ((ret = disconnect(sn)) != SOCK_OK) {
                printf("%d:disconnect fail\r\n", sn);
                return ret;
            }
            printf("%d: socket is closed\r\n", sn);
            break;
        
        default:
            break;
    }
    
    return 0;
}

4. 实现效果

将编写的demo文件加入到工程中,在main.c中声明一下该测试函数:

extern int tcp_server(uint8_t sn, uint16_t port);

因为该函数的实现是状态机,所以在while(1)中调用:

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
	/* USER CODE END WHILE */
	
	/* USER CODE BEGIN 3 */
	tcp_server(0, 8000);
}
/* USER CODE END 3 */

编译,下载到开发板中,使用串口助手查看结果:

在PC上运行socket调试助手,建立一个tcp client连接开发板:

TCP客户端连接之后,可以看到开发板打印出的信息:

接着在网络调试助手中发送信息:

可以看到,网络调试助手发送之后,收到了开发板回发的消息,在开发板上也可以看到日志:

当TCP客户端断开链接后,查看开发板串口日志:

三、TCP客户端的实现

1. 实现功能

实现一个TCP客户端,可以发起TCP客户端的请求,先向服务器发送数据,然后接收服务器回发的数据之后打印。

2. TCP客户端状态机

3. 实现代码

编写demo文件tcp_client.c

#include "socket.h"
#include <stdio.h>
#include <string.h>

#define DEFAULT_PORT            6000
#define DATA_BUF_SIZE			2048
static uint8_t send_buf[DATA_BUF_SIZE];
static uint8_t recv_buf[DATA_BUF_SIZE];

int tcp_client(uint8_t sn, uint8_t *dest_ip, uint16_t dest_port)
{
    int8_t ret;
    uint16_t recv_size = 0;
    uint16_t send_size = 0;
    
    switch (getSn_SR(sn)) {
    
        case SOCK_CLOSED:
            /* open socket */
            printf("TCP client start\r\n");
            if ((ret = socket(sn, Sn_MR_TCP, DEFAULT_PORT, 0x00)) != sn) {
                printf("socket %d open fail\r\n", sn);
                return ret;
            }
            printf("socket %d open success\r\n", sn);
            break;
        
        case SOCK_INIT:
            /* connect server */
            printf("try to connect %d.%d.%d.%d:%d...\r\n", dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3], dest_port);
            if ((ret = connect(sn, dest_ip, dest_port)) != SOCK_OK) {
                return ret;
            }
            break;
        case SOCK_ESTABLISHED:
            /* socket has been established */
            if(getSn_IR(sn) & Sn_IR_CON) {
                printf("%d:Connected to - %d.%d.%d.%d : %d\r\n",sn, dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3], dest_port);
                setSn_IR(sn,Sn_IR_CON);
            }
            
             // get the size of recv data in recv buffer
            if ((recv_size = getSn_RX_RSR(sn)) > 0) {
                if (recv_size > DATA_BUF_SIZE) {
                    recv_size = DATA_BUF_SIZE;
                }
                
                //recv data
                ret = recv(sn, recv_buf, DATA_BUF_SIZE);     
                if (ret <= 0) {
                    printf("%d:recv fail\r\n", sn);
                    return ret;
                } else {
                    // The actual received size
                    recv_size = (uint16_t)ret;
                    printf("%d:recv size:%d\r\n", sn, recv_size);
                    recv_buf[recv_size] = '\0';
                    printf("%d:recv data:[%s]\r\n", sn, recv_buf);
                }
                
                  //send data
                strcpy((char*)send_buf, "Hello, Server!");
                ret = send(sn, send_buf, strlen((char*)send_buf));
                if (ret <= 0) {
                    printf("%d:send fail\r\n", sn);

                    //close the socket
                    close(sn);

                    return ret;
                } else {
                    // The actual sent size
                    send_size = (uint16_t)ret;
                    printf("%d:send size:%d\r\n", sn, send_size);
                    //recv_buf[size] = '\0';
                    printf("%d:send data:[%s]\r\n", sn, send_buf);
                } 
            }
            break;
            
        case SOCK_CLOSE_WAIT:
            /* closing the socket */
            if ((ret = disconnect(sn)) != SOCK_OK) {
                printf("%d:disconnect fail\r\n", sn);
                return ret;
            }
            printf("%d: socket is closed\r\n", sn);
            break;
        
        default:
            break;
    }
    
    return 1;
}

在main.c中定义目标地址和目标端口:

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
uint8_t dest_ip[4] = {192, 168, 10, 156};
uint16_t dest_port = 8000;

/* USER CODE END PV */

声明测试函数:

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
extern int tcp_client(uint8_t sn, uint8_t *dest_ip, uint16_t dest_port);

/* USER CODE END 0 */

在while(1)中循环调用:

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
	/* USER CODE END WHILE */
	
	/* USER CODE BEGIN 3 */
	tcp_client(0, dest_ip, dest_port);
}
/* USER CODE END 3 */

4. 实验结果

首先在电脑上使用网络调试助手建立一个TCP服务器,在8000端口:

然后编译下载程序:

在网络调试助手中发送消息,可以看到开发板收到数据后回发的消息:

在开发板一侧也可以看到日志:

标签:02,W5500,TCP,dest,ret,sn,printf,recv,size
来源: https://blog.csdn.net/Mculover666/article/details/116860125

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有