灵动微课堂 (第186讲) | 基于MM32F3270 以太网 Server使用
来源:灵动MM32MCU发布时间:2021-10-14994浏览
询问 AI前面重点对Client的创建方式及使用方式进行了介绍,本节通过Server实验对TCP通信过程进行一次介绍。
在TCP/IP协议中,传输层及以下层的机制是由内核提供的。应用层由用户提供,应用层程序对通信数据进行解析处理,传输层及以下层处理通信的细节(将数据从一端传入另外一端)。应用层数据通过协议栈发送到网络上时,每层协议都要增加一个数据部首(header),进行一次封装。其中不同的协议层对数据包有不同的称谓,在传输层叫段(segment),在网络层叫做数据报(datagram),在链路层称为帧(frame)。


在通信过程中,发送端执行以下动作:首先程序进行编码,确定通信的建立连接、发送数据的时间。接着建立TCP连接,TCP根据应用指示负责建立连接、发送数据及断开连接。TCP首部包括源端口号和目标端口号、序号和校验和,加完首部后数据包继续往下传递到IP层,IP层加上IP首部包括地址等信息用于寻址操作,之后将数据继续往下传递附加数据链路层首部。最后发送时的分组数据包会加上以太网包尾(用于循环冗余校验)。
主机端:收到数据包后会在以太网数据包中找到MAC地址,判断是否为自己的数据包,如果不是则丢弃。如果是传递给IP层处理,以此类推,不断往上传递到TCP层。在TCP层通过校验和判断数据是否损坏,然后检查是否按序号接收数据,最后检查端口号。处理完成这一切后数据包继续往上层发送,即应用层。如果出现主机空间已满等情况,主机则会发送“处理异常”通知发送端。

实验使用MB-039开发板,在工程中使用LwIP+FreeRTOS,实验展示如何制作一个TCP Server,并收发数据,实验使用到的硬件如下:

如图是MB-039(完整原理图可以通过MM32官网下载)的ETH部分。
各个信号引脚对应如下:


在进行Server实验前,我们先了解需要使用到的API:
1)netconn_bind ()
2)netconn_listen ()
3)netconn_accept ()
以下分API展开介绍:
01 netconn_bind ()
err_tnetconn_bind(struct netconn* conn,constip_addr_t* addr,u16_tport)
{
API_MSG_VAR_DECLARE(msg);
err_terr;
LWIP_ERROR(netconn_bind: invalid conn", (conn !=NULL),returnERR_ARG;);
#ifLWIP_IPV4
* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
if(addr ==NULL) {
addr = IP4_ADDR_ANY;
}
#endif* LWIP_IPV4 */
#ifLWIP_IPV4 && LWIP_IPV6
if((netconn_get_ipv6only(conn) ==0) &&
ip_addr_cmp(addr, IP6_ADDR_ANY)) {
addr = IP_ANY_TYPE;
}
#endif* LWIP_IPV4 && LWIP_IPV6 */
API_MSG_VAR_ALLOC(msg);
API_MSG_VAR_REF(msg).conn = conn;
API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
API_MSG_VAR_REF(msg).msg.bc.port = port;
err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg));
API_MSG_VAR_FREE(msg);
returnerr;
}
02 netconn_listen ()
err_tnetconn_listen_with_backlog(struct netconn* conn,u8_tbacklog)
{
#ifLWIP_TCP
API_MSG_VAR_DECLARE(msg);
err_terr;
* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
LWIP_UNUSED_ARG(backlog);
LWIP_ERROR(netconn_listen: invalid conn", (conn !=NULL),returnERR_ARG;);
API_MSG_VAR_ALLOC(msg);
API_MSG_VAR_REF(msg).conn = conn;
#ifTCP_LISTEN_BACKLOG
API_MSG_VAR_REF(msg).msg.lb.backlog = backlog;
#endif* TCP_LISTEN_BACKLOG */
err = netconn_apimsg(lwip_netconn_do_listen, &API_MSG_VAR_REF(msg));
API_MSG_VAR_FREE(msg);
returnerr;
#else* LWIP_TCP */
LWIP_UNUSED_ARG(conn);
LWIP_UNUSED_ARG(backlog);
returnERR_ARG;
#endif* LWIP_TCP */
}03 netconn_accept ()
netconn_accept(代码较长,这里不进行粘贴)用于TCP服务器中,等待着远端主机的连接请求,并且建立一个新的TCP连接,在调用这个函数之前需要通过调用 listen()函数让服务器进入监听状态。accept()函数的调用会阻塞应用线程直至与远程主机建立TCP连接。参数addr是一个返回结果参数,它的值由accept()函数设置,其实就是远程主机的地址与端口号等信息,当新的连接已经建立后,远端主机的信息将保存在连接句柄中,能够标识连接对象。
了解了以上3个API,我们开始创建Server工程:
staticvoidserver(void* thread_param)
{
structnetconn*conn, *newconn;
err_terr;
LWIP_UNUSED_ARG(arg);
#ifLWIP_IPV6
conn = netconn_new(NETCONN_TCP_IPV6);
netconn_bind(conn, IP6_ADDR_ANY, LOCAL_PORT);
#else* LWIP_IPV6 */
conn = netconn_new(NETCONN_TCP);①
netconn_bind(conn, IP_ADDR_ANY, LOCAL_PORT);②
#endif* LWIP_IPV6 */
LWIP_ERROR(tcpecho: invalid conn", (conn !=NULL),return;);
printf(The local port number is%d\n\n", LOCAL_PORT);
netconn_listen(conn);③
while(1) {
err = netconn_accept(conn, &newconn);④
if(err == ERR_OK) {
structnetbuf*buf;
void* data;
u16_tlen;
while((err = netconn_recv(newconn, &buf)) == ERR_OK) {⑤
do{
netbuf_data(buf, &data, &len);
err = netconn_write(newconn, data, len, NETCONN_COPY);⑥
}while(netbuf_next(buf) >=0);
netbuf_delete(buf);⑦
}
netconn_close(newconn);⑧
netconn_delete(newconn);⑨
}
}
}1 申请一个连接结构,指定参数是NETCONN_TCP,即TCP连接
2 绑定本地的IP地址与端口号
3 使TCP服务器进入监听状态
4 处理客户端的连接请求,当只有当有客户端发送连接请求的时候才会处理,否则将进入阻塞态,而客户端的信息保存在newconn连接结构中
5 接收数据,并装填进buf
6 对接收的数据进行转发(指定为不拷贝方式NETCONN_COPY)
7 释放数据空间
8 主动关闭客户端的连接
9 释放newconn空间
到这里已经完成了工程的创建,看一下PC的IP地址,设备需要处于同一网段,以方便测试。
打开命令行窗口输入:ipconfig

PC的地址为:192.168.105.34,在sys_arch.h文件中对DEST_IP_ADDR0 、DEST_IP_ADDR1、DEST_IP_ADDR2、DEST_IP_ADDR3进行修改,DEST_PORT 随意修改。
#defineLOCAL_PORT 2021
#defineIP_ADDR0 192
#defineIP_ADDR1 168
#defineIP_ADDR2 105
#defineIP_ADDR3 21
将程序下载入开发板中,使用NetAssist进行如下设置:
1)协议设置,此时设备为Server,则PC为Client
2)设置远程主机地址(即设备地址)
3)端口号

点击连接,若提示连接失败,则Ping一下开发板地址,可以正常Ping通则检查端口号;如果无法Ping通则需要对工程进行检查。

任意输入字符进行发送。

通过上图可以观察到发送成功,并且设备返回数据与发送数据一致,表明实验成功。实验程序请登录我们的官网(https://www.mindmotion.com.cn/download.aspx?cid=2542&page=2)下载MM32F3270 SDK,工程路径如下:~\MM32F3270_Lib_Samples_V0.90\Demo_app\Ethernet_Demo\ETH_RTOS\Freertos_Server。
我们下章的题目为《基于MM32F3270 以太网 HTTP使用.docx》,实现Webserver的使用。
新闻来源:灵动MM32MCU,文中所述为作者独立观点,不代表icspec立场。更多精彩资讯请下载icspec App。如对本稿件有异议,请联系微信客服specltkj。


