TCP比UDP就复杂多了,UDP就像串口一样发发随便奶奶,但是TCP不是,有监听啊,查询啊什么,可以看看电脑的TCP连接,多得呢.
所以,在官方的例子你们,TCP Client就是6个函数:
static err_t tcp_echoclient_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err); static void tcp_echoclient_connection_close(struct tcp_pcb *tpcb, struct echoclient * es); static err_t tcp_echoclient_poll(void *arg, struct tcp_pcb *tpcb); static err_t tcp_echoclient_sent(void *arg, struct tcp_pcb *tpcb, u16_t len); static void tcp_echoclient_send(struct tcp_pcb *tpcb, struct echoclient * es); static err_t tcp_echoclient_connected(void *arg, struct tcp_pcb *tpcb, err_t err);
而TCP Server则有7个那么多.
static err_t tcp_echoserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err); static err_t tcp_echoserver_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err); static void tcp_echoserver_error(void *arg, err_t err); static err_t tcp_echoserver_poll(void *arg, struct tcp_pcb *tpcb); static err_t tcp_echoserver_sent(void *arg, struct tcp_pcb *tpcb, u16_t len); static void tcp_echoserver_send(struct tcp_pcb *tpcb, struct tcp_echoserver_struct *es); static void tcp_echoserver_connection_close(struct tcp_pcb *tpcb, struct tcp_echoserver_struct *es);
形象地说,TCP模拟成一个教室的通信,而TCP Server时候,你就是老师,而TCP Client时候,你就是学生,老师可以接受很多学生提问,也可以给单独一个学生说话,也可以群体发话,学生之间不能之间聊天,只能跟老师说话.TCP Server和TCP Client可以共存在一个板子上,他们端口肯定是不一样的.如果是TCP Server,老师,只要知道课室是哪个,就能找到学生,而学生要找老师,就得跟着老师去了哪个课室,这样,是不是挺好理解的.
我们用官方的例子,但是进行一些分析.首先是创建一个老师啊.
void tcp_echoserver_init(void) { tcp_echoserver_pcb = tcp_new(); if (tcp_echoserver_pcb != NULL) { err_t err; err = tcp_bind(tcp_echoserver_pcb, IP_ADDR_ANY, 7); /* TCP绑定 */ if (err == ERR_OK) { tcp_echoserver_pcb = tcp_listen(tcp_echoserver_pcb); /* 开始监听(等学生来) */ tcp_accept(tcp_echoserver_pcb, tcp_echoserver_accept); /* 如果有什么动静,需要通知我,这个函数. */ } } }
然后再生成回调:
static err_t tcp_echoserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { if (es != NULL) { /* 当收到数据时 */ tcp_recv(newpcb, tcp_echoserver_recv); /* 当出错时 */ tcp_err(newpcb, tcp_echoserver_error); /* 当轮询时 */ tcp_poll(newpcb, tcp_echoserver_poll, 1); ret_err = ERR_OK; } }
对于收到数据的处理方法:
static err_t tcp_echoserver_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { /* 空TCP数据 */ if (p == NULL) { ret_err = ERR_OK; } /* 非空但是数据不正确 */ else if(err != ERR_OK) { ret_err = err; } /* 连接成功 */ else if(es->state == ES_ACCEPTED) { ret_err = ERR_OK; } /* 收到数据 */ else if (es->state == ES_RECEIVED) { ret_err = ERR_OK; } /* 连接关闭后还能收到数据 */ else { ret_err = ERR_OK; } return ret_err; }
然后这个其实只需要tcp_echoserver_init,后续就一切可以了.一直监听,如果有数据,就会进入处理流程.
如果我们作为Client,就不断的发送新数据给老师(服务器).所以要知道老师的地址.所以,连接时候不一样,其他逻辑基本一样.
void tcp_echoclient_connect(void) { struct ip_addr DestIPaddr; /* create new tcp pcb */ echoclient_pcb = tcp_new(); if (echoclient_pcb != NULL) { IP4_ADDR( &DestIPaddr, DEST_IP_ADDR0, DEST_IP_ADDR1, DEST_IP_ADDR2, DEST_IP_ADDR3 ); /* connect to destination address/port */ tcp_connect(echoclient_pcb,&DestIPaddr,DEST_PORT,tcp_echoclient_connected); } else { /* deallocate the pcb */ memp_free(MEMP_TCP_PCB, echoclient_pcb); #ifdef SERIAL_DEBUG printf(" can not create tcp pcb"); #endif } }
其他都是一样的,那么,对于TCP的高级应用,TCP Web,就没什么难度了,就不多说了.例程: