|
//===================================================================== b$ R0 W1 \7 j3 }# z0 s. U* b
//TITLE:
7 Y5 @9 g5 n3 l// STM32F2xx的tcp_echoserver例程解说/ i2 N5 o% t/ O" p6 M
//AUTHOR:) Y* ^7 h: W: W! k) x) l
// norains
: J* c, ^* _: h//DATE:
+ k8 m9 ?: n' f// Monday 04-July-2011
0 b( G# y2 G# e/ D//Environment:$ ~9 t1 L% l: J( Y
// Keil MDK 4.2
. b5 A) e& a) r$ f5 t// STM32F207 核心版
6 I6 |9 m3 A. w: K& r6 c//===================================================================== 最近拿到STM32F207的核心版,板载有网卡芯片,自然要拿过来捣鼓一番。而对于一个从未接触过网络的菜鸟来说,最好的入门方式就是揣测ST公司的例程,所以今天norains也不例外。那么我们就一起来看看这个官方的例程吧! " j8 t% ^# J5 o) z x
ST关于TCP的例程分为client和server,根据字面意思,可以知道tcp_echoserver例程是将STM32F2xx作为server来用。而例程的第一步呢,便是初始化,调用的是tcp_echoserver_init()函数。 在tcp_echoserver_init()函数里,主要做了这么几件事情:
/ F9 R' Y; ~1 A9 q+ Y* _7 p# I 1. 创建一个新的TCP协议控制块
& G4 \8 W6 v& i, R0 z1 h 2. 绑定地址和端口号(port): y0 H+ K$ T+ Q+ B6 m- ]
3. 开始监听(listen)
( F. U4 U8 d$ ? 4. 设置accept的回调函数 其完整代码如下: - void tcp_echoserver_init(void)
, f' J/ @4 Z1 z- \ - { 9 y6 E& J6 V% N
- //创建一个新的TCP控制块
: F! _8 D }5 u2 |: @9 q- T - tcp_echoserver_pcb = tcp_new(); 7 u# k+ t0 c8 C N& u" n2 L
-
3 ]+ V& v; b) p5 O# v* R( H - if (tcp_echoserver_pcb != NULL) , i5 f9 `3 J; A! X' a5 h5 C
- {
9 X, v! U/ }# l. D) @! m9 a; B - err_t err;
, M% N ^" i7 u9 Y Y2 w - . @0 `. f6 y* e; V
- //绑定到端口7
) `. I+ D9 m j: A5 s, l' i - err = tcp_bind(tcp_echoserver_pcb, IP_ADDR_ANY, 7);
7 f# v; f3 h+ t( z' K* _ - $ r5 x6 \$ p* I7 o v
- if (err == ERR_OK)
" q, H( @% _' F5 F' x/ K! E, ] - { # t2 X! u4 I* M& w! U! n* M4 z
- //开始监听 2 x" z: d+ p0 M/ a" U- v+ v
- tcp_echoserver_pcb = tcp_listen(tcp_echoserver_pcb); 6 q# b4 k8 b& F1 o! k# T$ d
- " C1 `2 O/ K0 V' h; @
- //设置tcp_echoserver_accept为accept的回调函数
# L% i. G0 P- Z' u+ e - tcp_accept(tcp_echoserver_pcb, tcp_echoserver_accept);
, E6 g6 A% y8 X$ R5 |2 l - } % i3 f! O0 ^% z$ T5 w
- else
% N: L9 H% X; @# O7 {( R* L2 O - { - Q$ r- I0 e: f) R
- printf("Can not bind pcb\n"); //norains 2011-7-4 comment
8 \2 {; u$ W6 z1 i$ F; m$ C( N( M - } & A7 N7 t) G: c' J3 [3 l
- } " ^5 Q9 ^7 c4 S* Y) _, Y9 w, h5 v
- else
j9 m- w, ?, x' H* Y- n/ c5 s% G - {
& x) r/ K, F( r6 f* |- [ - printf("Can not create new pcb\n"); //norains 2011-7-4 comment a; Y \% ]" q( M9 y
- }
% c. b3 Y1 Z$ n# ^! E0 ^9 i - }
复制代码 当客户端开始连接之后,那么被设置的tcp_echoserver_accept()回调函数就会被调用。该函数主要是创建一个新的数据结构,并且将该数据结构传递给底层的TCP,最后分别是设置receive,error和poll这三个回调函数。) N! L% U, g2 j
) f0 a9 s: Z3 G j2 M* B2 m2 m+ z tcp_echoserver_accept()代码如下所示: - static err_t tcp_echoserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err) % Q: ~/ j" O. U, n* W, f* u$ D) e
- { 8 b) U5 ~ A$ [/ C: w& ^; y
- err_t ret_err; . w. ]5 u4 H' j& A/ x
- struct tcp_echoserver_struct *es; ; h' a2 E$ g( W0 i1 w6 e
- 6 ^1 i" Q0 c6 L
- LWIP_UNUSED_ARG(arg); 3 G U3 b$ d) m8 J2 a8 v
- LWIP_UNUSED_ARG(err);
' E f8 T' M- F9 [' V -
6 `+ f5 d0 I! `0 g& O9 F/ f0 D - ///给新的连接设置优先级
T; ?9 q4 o* M1 T! L0 G% `) a; i: W A( y - tcp_setprio(newpcb, TCP_PRIO_MIN); , w2 ~( R0 R' [8 W3 X4 l
-
( J; Y9 W6 Z% t1 ~ - //分配一个结构体空间以保持TCP的连接
, w( [3 t+ G* J7 J2 z - es = (struct tcp_echoserver_struct *)mem_malloc(sizeof(struct tcp_echoserver_struct)); . V m, o! U W1 R
- if (es != NULL) " b) P1 G* n% |: f! z
- { 8 {) `8 Y! b% w& f# |4 }& b4 Z
- es->state = ES_ACCEPTED;
8 [6 ~: q# n6 B2 M) U8 L7 o1 g8 j - es->pcb = newpcb;
( n% J5 v' _& B8 g" A - es->p = NULL; & F3 w: f8 j/ H( B2 X6 s; }2 }
- % H# t1 l* P u# h9 @
- //传递新分配的结构体数据给新的pcb
! S% t' T6 l1 ] - tcp_arg(newpcb, es);
6 i, d' q4 _, y% } -
. ~4 [3 E0 v* F! T" M% H9 J- Z. Q) L - //为新的连接设置receive回调函数
0 n5 ]+ T$ t2 A& a# T# @ - tcp_recv(newpcb, tcp_echoserver_recv);
7 L9 \1 J5 G, K6 w -
: Q( Y6 J$ [8 w9 `/ ~/ z - //为新的连接设置error回调函数
& M6 A) }; F* n1 ~# ] - tcp_err(newpcb, tcp_echoserver_error); ; G F4 v) ^' ] F/ i/ i" M! ]
-
! O$ L$ Q' m/ V3 Y* D+ Y: } - //为新的连接设置poll回调函数
1 a/ s. [3 x/ f - tcp_poll(newpcb, tcp_echoserver_poll, 1);
; {3 ~9 o8 t+ b( @: g9 Y$ G7 h - $ M+ F2 a( I& [" m/ {; d- w' Q
- ret_err = ERR_OK;
. E( z3 \% S8 T5 P - }
7 t+ z* N: q6 M8 S8 N1 R0 O+ F8 Z - else S- U: m: s" e( Z% ^
- {
0 d% u; |) W) x9 ` - /* return memory error */ $ U7 c( {$ F/ [1 k/ d
- ret_err = ERR_MEM; 0 s& `) r5 j9 R
- }
) O! L+ G/ L; f4 U' m; K1 {- ` - return ret_err;
: K7 J, Z% F* G' E9 l - }
复制代码 接下来便是tcp_echoserver_recv()这个回调函数,因为该函数比较大,这里就不再全部罗列代码了。对于使用者来说,只需要知道相应的判定条件来代表什么意思就足够了,如:% Y' I" j. \3 G$ G0 S, Q5 |
- static err_t tcp_echoserver_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
; W- k6 z- \7 p& F - { . C% H3 m$ v/ i/ B; J0 j% [
- struct tcp_echoserver_struct *es; 6 ]$ Q. N! p1 j1 N
- err_t ret_err; - \+ p) r3 o, {% Z% |- j
- . |) `1 w4 `8 Q* g9 u: p& z
- LWIP_ASSERT("arg != NULL",arg != NULL); / S7 D# ?9 y) |4 ^& ^% Y- b( @
- & e" X& c. |% T5 h, P J$ q8 x5 b
- es = (struct tcp_echoserver_struct *)arg; * d' |. w3 o" e. H
-
. ^" F) r1 a/ Q - if (p == NULL)
! l+ H- |( I" Y& `. h/ A5 L. D - { 5 B+ B$ v" O2 b6 U3 [
- //如果接收到空的帧,则释放连接
9 [% h8 x* x* L! Y5 F: u; F - ... 6 t7 o; u( A# i0 q" J
- } 2 j6 k2 [) F. Y2 r) f8 ?( k
- else if(err != ERR_OK) 5 J. V2 \9 l' H' e4 h/ H
- {
, S' {: e% I! w - //接收到一个非空的帧,但可能某些原因出错,导致返回值不为ERR_OK,故在此释放缓存 5 \, Y$ C2 M( H
- ...
6 @# S6 C. ~' a+ W6 @" m8 c$ ` - } 4 w& K' x2 u4 g! p* E
- else if(es->state == ES_ACCEPTED) 0 y) X$ ~3 e* g$ J& z5 y
- {
& T$ p: h. f/ S7 r, {7 Q- p - //连接成功,在这里需要设置sent回调函数
6 w; d$ p: n% X1 q - ... ( M2 k3 I( E# | r8 p: O E7 z
- } 4 Q( H* b8 C- H
- else if (es->state == ES_RECEIVED)
) C' A; X2 X2 Z, ` - {
* S. ]' L$ h5 G7 v5 o& M4 Y# H. h - //从客户端收到数据
x- L2 G$ ~" _+ T9 t - ...
, G* d% |; m8 [" D4 T - }
* F3 L4 G m. B. W: a& y# s - else 5 J) Q+ _7 w+ i; _) F! A4 A
- {
3 }/ b8 h5 Q! p/ v& O# `0 P4 W - //当连接关闭时,还收到了数据 # q7 T$ Y6 l& b
- ...
" a6 v9 V4 Z6 u* m L L5 f - * x) A) G0 \, k' ]2 C
- }
; P( Z5 B, g$ p) s8 B# b) ]; l - 3 c% @! d' z- u. c6 z- x
- return ret_err;
/ ?; @9 d& _. s - }
复制代码 STM32F207的代码部分就暂时说到这里,现在的问题是,如何 测试这代码的正确性呢?这就必须用到ST提供的echotool.exe程序了。该程序位于stm32f2x7_eth_lwip的PC_Software文件夹中。该程序必须在命令行打开,其大致参数如下所示:
X) B2 d+ \$ X# u1 X# E
' x; b5 K. B$ x' J0 Z+ O4 U5 H. _, u( W5 a3 d, `# `8 _8 M
) R8 h, i/ n$ ]$ I8 h% n( @# f
如果我们的serverip地址为192.168.0.8,那么可以输入如下命令进行测试:/ c9 @) Z2 t6 K5 A1 A/ r
echotool.exe 192.168.0.8 /p tcp /r 7 /n 15 /t 2 /d Testing LwIP TCP echo server1 k5 N7 B8 v9 }: d+ S6 F
Z1 A1 B9 P/ Y3 \5 p4 u 如果网络联通的话,测试成功将如下如下的画面,如图:$ M0 X2 X! {! T3 q( t( w
) { r6 T! \4 [7 m- D, h' ?' V
* x9 H* }1 @: N& U7 Z
6 p- s5 Z! Q* R% ~3 u6 {6 w! c g, E& _$ }% n7 N% s5 \2 r
# r- B. M h$ Q0 `
9 z3 a: g& ]; a3 m |