RAW实现TCP客户端和服务器的创建-STM32F767

 参考文章:【LWIP】stm32用CubeMX(6.4版)配置LwIP+Ping+TCPclient+TCPserver发送信息到PC(操作部分)_cubemx lwip-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/lrqblack/article/details/123791613

1 TCP控制块

tcp控制块定义在tcp.h文件中

LWIP中将TCP控制块组合成链表的形式,如图:

2 TCP回调函数

函数描述
tcp_arg()注册回调函数使用的参数

tcp_recv()

注册接收的回调函数
tcp_err()注册出错处理的回调函数
tcp_sent()注册发送成功的回调函数
tcp_poll()注册轮询函数
tcp_accept()当侦听到有客户端连接的话就会调用注册函数

3 TCP实现原理

4 TCP函数

函数API描述
TCP建立连接tcp_new创建一个TCP的PCB控制块
tcp_bind绑定一个本地IP和PORT
tcp_listen监听TCP
tcp_accept注册监听回调函数
tcp_connect连接远程主机
发送TCP数据tcp_write将数据发送至发送缓冲区队列当中
tcp_sent注册发送完成回调函数
tcp_output将发送缓冲队列中的数据发送出去
接收TCP数据tcp_recv注册接收完成回调函数
tcp_recved通知内核更新接收窗口
关闭连接tcp_close关闭TCP连接
tcp_abort终止TCP连接

5 RAW接口的TCPClient实验

(1)tcp_new创建一个TCP控制块; //描述当前TCP端口、IP等信息

(2)tcp_connect设置目标IP地址和插入TCP_PCB链表;//把控制块插入TCP PCB链表

(3)tcp_recv注册接收回调函数; //接受回调函数自行编写

(4)tcp_write发送数据; //网络搭建完成后,发送数据

6 TCPClient代码

​

#include "lwip/netif.h"
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include "lwip/init.h"
#include "netif/etharp.h"
#include "lwip/udp.h"
#include "lwip/pbuf.h"
#include <stdio.h>	
#include <string.h>
#include "main.h"
#include "tcpClient.h"



static void client_err(void *arg, err_t err)       //出现错误时调用这个函数,打印错误信息,并尝试重新连接
{
  printf("连接错误!!\n");
  printf("尝试重连!!\n");
  
  /* 连接失败的时候释放TCP控制块的内存 */
  printf("关闭连接,释放TCP控制块内存\n");
  /* 重新连接 */
  printf("重新初始化客户端------------\r\n");
  TCP_Client_Init();
}


static err_t client_send(void *arg, struct tcp_pcb *tpcb)   //发送函数,调用了tcp_write函数
{
  uint8_t send_buf[]= "tcp客户端测试-----------\r\n";
  
  //发送数据到服务器
  tcp_write(tpcb, send_buf, strlen(send_buf), 1); 
  
  return ERR_OK;
}

static err_t client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
  if (p != NULL) 
  {        
    /* 接收数据*/
    tcp_recved(tpcb, p->tot_len);   
//    /* 返回接收到的数据*/  
//    tcp_write(tpcb, p->payload, p->tot_len, 1);
    int i = 0;
    for(i = 0; i < p->len;i++)
    {
      printf("%c",*((char *)p->payload+i));
    }
    memset(p->payload, 0 , p->tot_len);
    pbuf_free(p);
  } 
  else if (err == ERR_OK) 
  {
    //服务器断开连接
    printf("服务器断开连接---------\r\n");
    tcp_close(tpcb);
    
    //重新连接
    TCP_Client_Init();
  }
  return ERR_OK;
}

static err_t client_connected(void *arg, struct tcp_pcb *pcb, err_t err)
{
  printf("connected ok-------------\r\n");
  if(err == ERR_OK)
  {
    
    tcp_err(pcb, client_err); //注册异常处理
    printf("已经注册异常处理函数\r\n");
 
    tcp_poll(pcb,client_send,10);//注册一个周期性回调函数
    printf("已经注册了周期回调函数\r\n");
   
    tcp_recv(pcb,client_recv); //注册一个接收函数
    printf("已经注册了接收回调函数\r\b");
  }
  
  return ERR_OK;
}


void TCP_Client_Init(void)
{        
  struct tcp_pcb *client_pcb = NULL;   
  ip4_addr_t server_ip;     //因为客户端要主动去连接服务器,所以要知道服务器的IP地址
  /* 创建一个TCP控制块  */
  client_pcb = tcp_new();	  
  
  IP4_ADDR(&server_ip, 192,168,2,87);//合并IP地址

  printf("客户端开始连接-------------\r\n");
  
  //开始连接
  tcp_connect(client_pcb, &server_ip, TCP_CLIENT_PORT, client_connected);
  ip_set_option(client_pcb, SOF_KEEPALIVE);	
  printf("已经调用了tcp_connect函数\n");	
}

[点击并拖拽以移动]
​

7 TCPServer代码

#include "tcpserver.h"
#include "lwip/netif.h"
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include "lwip/init.h"
#include "netif/etharp.h"
#include "lwip/udp.h"
#include "lwip/pbuf.h"
#include <stdio.h>	
#include <string.h>


static err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{                                   //对应接收数据连接的控制块   接收到的数据   
  if (p != NULL) 
  { 
    int i = 0;
    /* 更新窗口*/
    tcp_recved(tpcb, p->tot_len);     //读取数据的控制块   得到所有数据的长度   
    for(i = 0; i < p->len;i++)
    {
      printf("%c",*((char *)p->payload+i));
    }
    /* 返回接收到的数据*/  
  //tcp_write(tpcb, p->payload, p->tot_len, 1);
    const char reback[] = "已经收到了数据";
    tcp_write(tpcb, reback, strlen(reback), 1);	
    
    memset(p->payload, 0 , p->tot_len);
    pbuf_free(p);
  } 
  else if (err == ERR_OK)    //检测到对方主动关闭连接时,也会调用recv函数,此时p为空
  {
    printf("客户端连接断开");
    return tcp_close(tpcb);
  }
  return ERR_OK;
}

static err_t tcp_server_accept(void *arg, struct tcp_pcb *newpcb, err_t err)																																				//形参的数量和类型必须一致
{     

  tcp_recv(newpcb, tcp_server_recv);    //当收到数据时,回调用户自己写的tcpecho_recv
  return ERR_OK;
}

void TCP_Server_Init(void)
{
  struct tcp_pcb *server_pcb = NULL;	            		
  /* 创建一个TCP控制块  */
  server_pcb = tcp_new();	
  printf("创建了一个控制块\n");
  
  /* 绑定TCP控制块 */
  tcp_bind(server_pcb, IP_ADDR_ANY, TCP_SERVER_PORT);       
  printf("已经绑定一个控制块\n");

  /* 进入监听状态 */
  server_pcb = tcp_listen(server_pcb);
  printf("进入监听状态\n");	

  /* 处理连接 注册函数,侦听到连接时被注册的函数被回调 */	
  tcp_accept(server_pcb, tcp_server_accept);  //侦听到连接后,回调用户编写的tcp_server_accept 
																	  //这个函数是*tcp_accept_fn类型的
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值