//=====================================================================* d. s+ V" u3 c6 d# Y+ p! n" i) D
//TITLE:
6 L. d% o7 V j, \3 N// STM32F2xx的tcp_echoserver例程解说
( ~' V" Q& c- N- X" q/ n* ?//AUTHOR:0 ~: y/ @5 B3 _$ r, S# i0 }
// norains
2 W. b3 _( n1 d! A. O+ ~//DATE:
, W( g1 T5 k b. b- t2 e// Monday 04-July-2011( I+ v4 {+ \5 O w; _3 O/ I f
//Environment:
' a0 A) Z# Y& t$ p# \// Keil MDK 4.22 w# X* x; t$ l2 a8 ?- J
// STM32F207 核心版
) J1 S+ Y. j6 ~% H) c6 w//===================================================================== 最近拿到STM32F207的核心版,板载有网卡芯片,自然要拿过来捣鼓一番。而对于一个从未接触过网络的菜鸟来说,最好的入门方式就是揣测ST公司的例程,所以今天norains也不例外。那么我们就一起来看看这个官方的例程吧! ) t0 n' q& g% |
ST关于TCP的例程分为client和server,根据字面意思,可以知道tcp_echoserver例程是将STM32F2xx作为server来用。而例程的第一步呢,便是初始化,调用的是tcp_echoserver_init()函数。 在tcp_echoserver_init()函数里,主要做了这么几件事情:9 X: F" Y8 d2 H. ?, V! k {/ s
1. 创建一个新的TCP协议控制块
* P# W8 W! A0 |3 [7 t 2. 绑定地址和端口号(port)
1 w( j( }1 v7 l- e$ N" z 3. 开始监听(listen). c3 G- }! R& @5 @5 ~ D7 U
4. 设置accept的回调函数 其完整代码如下: - void tcp_echoserver_init(void)
( Q' a T& |: @9 S% | - {
* Y, W$ a5 L9 Q `2 z - //创建一个新的TCP控制块 2 ~8 I3 `, P' w, L
- tcp_echoserver_pcb = tcp_new();
- K1 J- h- b# h; P: ^1 ?/ B - & h9 D0 i- J* x) i
- if (tcp_echoserver_pcb != NULL)
( C- l/ P( n9 L4 d# U - { % E! W% i0 ]* i7 w
- err_t err;
7 G5 m% E! ]" \- _# v( _. ?- T7 A -
: ]9 t E4 s- i4 [6 ` - //绑定到端口7 & Z0 e/ F/ _$ G: y% ~# @
- err = tcp_bind(tcp_echoserver_pcb, IP_ADDR_ANY, 7);
) ]! Z; D f/ O8 I* A9 M) i" J f# Q - 8 l7 g, [- o0 R9 b/ X
- if (err == ERR_OK) 5 x' l- r6 ^: _( h
- {
/ C4 x- j `; ^ - //开始监听 ' Z* C% z* a9 I2 Z; ?
- tcp_echoserver_pcb = tcp_listen(tcp_echoserver_pcb); - W- i+ u1 y/ L# u/ a/ ]* U
- 5 P( u7 Y# Y( J
- //设置tcp_echoserver_accept为accept的回调函数 ; O- O$ d( E x8 G
- tcp_accept(tcp_echoserver_pcb, tcp_echoserver_accept);
4 m' o3 K( U! K# \' T( R# w - }
( G% n5 e' R+ z: [# J( n - else 9 z6 c% B2 @& F7 x4 j& t( K
- { ( e5 ^1 L9 b# q3 o9 R% F& c! L/ s
- printf("Can not bind pcb\n"); //norains 2011-7-4 comment . U( j4 ?' t( }/ E* N% A! }; q, Z: b, L
- } ; W; S3 [4 ?) a% b
- }
$ I( j2 L" p9 O, T6 w; S6 } - else 3 P" L( t- c. i0 q$ C
- {
, W' t! y7 d5 `# r; \+ R - printf("Can not create new pcb\n"); //norains 2011-7-4 comment
' Q8 q1 g" t% M - } & q, N6 g; B9 i1 o! ~3 o
- }
复制代码 当客户端开始连接之后,那么被设置的tcp_echoserver_accept()回调函数就会被调用。该函数主要是创建一个新的数据结构,并且将该数据结构传递给底层的TCP,最后分别是设置receive,error和poll这三个回调函数。8 u( a% e Q! Z
4 p6 P- I0 `8 ?1 e8 G& O tcp_echoserver_accept()代码如下所示: - static err_t tcp_echoserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
b. j2 M$ i7 |+ N7 f- t V! z: E - { 0 O) _+ ^- @9 ~. ~7 ?+ i% X, }
- err_t ret_err;
( ~! b! S7 p; f - struct tcp_echoserver_struct *es;
8 [! T: o, s2 Q% W% S" A$ o - , h$ F* x3 T8 N! b, L& }4 D
- LWIP_UNUSED_ARG(arg);
" s# o! l, C+ a# U - LWIP_UNUSED_ARG(err); + @1 Z3 {, K& L6 |
- 5 K% s7 f% Z6 D- h
- ///给新的连接设置优先级 8 m9 q8 V: K# U. N v& L' H
- tcp_setprio(newpcb, TCP_PRIO_MIN); 6 y4 K$ j, G% [ K9 B( ^
-
# j" @1 K, H! f8 Y2 k7 A - //分配一个结构体空间以保持TCP的连接
% Y2 O6 m* m' ?9 m4 _ - es = (struct tcp_echoserver_struct *)mem_malloc(sizeof(struct tcp_echoserver_struct));
8 t& g. i6 {0 E S - if (es != NULL) * k6 F5 P1 c; V3 l, o
- {
& u# ]8 N2 x' A1 Y( I$ N, ~' A2 K - es->state = ES_ACCEPTED;
7 x, A2 p* b+ e# w' Q - es->pcb = newpcb; # _# W e. T' T+ z- @. b$ l, {# Y) u
- es->p = NULL; " C/ |/ i6 O/ b! E6 ^
-
, Q# t" ^/ J7 p+ o$ m) U4 k - //传递新分配的结构体数据给新的pcb
* Y/ w2 t( q- O* ~/ w) o - tcp_arg(newpcb, es);
7 \! W" I) k$ K# ^% \3 E& q8 i -
6 l+ x4 x9 p. `. ~; ^$ R - //为新的连接设置receive回调函数
l5 c( N7 a8 P$ n% \3 I* @ - tcp_recv(newpcb, tcp_echoserver_recv);
) a$ |" y) Y, v' k) j4 Y -
$ [6 H, y( k; N7 b; H) { - //为新的连接设置error回调函数 3 S0 O: j8 J8 C
- tcp_err(newpcb, tcp_echoserver_error);
9 D" `5 T6 t5 o3 s! j - 7 \7 E* S; M2 i# q
- //为新的连接设置poll回调函数
) N1 t* ?; S) i: w7 T: v6 M2 N - tcp_poll(newpcb, tcp_echoserver_poll, 1); 3 z" D. T& B5 x/ U$ @, W
- " \8 u/ j5 O9 h1 U- f+ ^/ c
- ret_err = ERR_OK; / X& V m4 j" f3 g6 I3 X
- }
, y! Q: q# I6 L# c0 E" K - else : ^1 I7 [; R5 F U5 H: d. f7 C: z
- { 9 X I, \1 g5 P& o# c
- /* return memory error */ ; I8 H; w' _9 A9 u* U4 h9 _/ k& }* ?
- ret_err = ERR_MEM;
/ |8 ^) \1 L7 l( h) h7 L4 m8 B - }
- z. ^* E P0 y4 p! K: C" | - return ret_err;
4 r; h! q3 q6 `9 z2 \ - }
复制代码 接下来便是tcp_echoserver_recv()这个回调函数,因为该函数比较大,这里就不再全部罗列代码了。对于使用者来说,只需要知道相应的判定条件来代表什么意思就足够了,如:
: H4 W6 r! P8 N" H - static err_t tcp_echoserver_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) 1 i6 I1 s+ q1 _$ k
- {
# Q2 E' C% w9 y) r8 v5 r6 X' X - struct tcp_echoserver_struct *es;
: p- Y& J1 ^6 h - err_t ret_err;
, K+ J' ?& T. U - 4 i9 o0 F w7 X
- LWIP_ASSERT("arg != NULL",arg != NULL);
: B3 c2 }9 P( N* O$ W, h, B0 | -
9 f5 ^6 q I/ v& Z/ n& M5 F. s1 p j - es = (struct tcp_echoserver_struct *)arg;
( R7 N. D. t: [7 K, } -
, k$ i1 p9 j, u0 Y7 J - if (p == NULL)
2 f Q4 `' `0 M' N - { h; e" l+ o" G% F4 `
- //如果接收到空的帧,则释放连接 ) X. ^9 {1 u* E& P, h0 ^
- ... - d* p8 [/ \. t0 {5 k" e% ^8 K6 R8 r
- } 5 J. t) ` j# P# m. J/ @
- else if(err != ERR_OK) , f. G1 a, J3 ^1 a$ w9 e& z3 c, Z
- { ! B1 N3 z* z' E [* b% ^1 e% r% m" H
- //接收到一个非空的帧,但可能某些原因出错,导致返回值不为ERR_OK,故在此释放缓存
0 E8 S/ I( d( {9 y, O - ... 5 H1 P/ @0 s+ F' d
- }
3 _" E+ \% M/ R+ E: S4 R; S - else if(es->state == ES_ACCEPTED)
1 m. |* G; x* B, C3 c8 c% s. W$ q - { : W3 B9 R4 d. f" [6 Y
- //连接成功,在这里需要设置sent回调函数 5 J, Q% ]1 ]2 w2 C
- ... & E B+ u, f% B' r, W
- } & v' @% U1 L, I! |6 ^. P+ ~
- else if (es->state == ES_RECEIVED) # }, n* y( S7 _9 A" p. \3 _
- {
! Y1 N, G$ U5 H+ R! U - //从客户端收到数据 % l& _! j W1 {9 O1 p
- ...
) b ]. i$ f) ] - }
" x# w) F( \. D3 h - else 3 ^9 O- ?6 y& g( e3 K/ B* z
- {
* T8 U3 ?% ^7 W( _, `7 B- J - //当连接关闭时,还收到了数据 . g# J% ~% O- h
- ...
$ s$ b$ L$ z& |0 X- u7 u" x -
. [2 L: @" [0 L# I/ U, \ - } - x2 X4 |! c* t
-
: e: q+ T" I6 N$ w% Q - return ret_err; * @' @1 I; z! W# e7 T
- }
复制代码 STM32F207的代码部分就暂时说到这里,现在的问题是,如何 测试这代码的正确性呢?这就必须用到ST提供的echotool.exe程序了。该程序位于stm32f2x7_eth_lwip的PC_Software文件夹中。该程序必须在命令行打开,其大致参数如下所示:
+ I8 {* I v' z) }
$ [* V. _5 ^) ?) j
4 Z# E ?5 v0 w0 `2 ]1 d9 E
. A6 M9 k* D7 {4 m0 F9 M 如果我们的serverip地址为192.168.0.8,那么可以输入如下命令进行测试:
, V% C- Q4 q1 X: D9 `) K echotool.exe 192.168.0.8 /p tcp /r 7 /n 15 /t 2 /d Testing LwIP TCP echo server
1 s& {& J+ i' x; Z2 I* [ b* }
2 C& g9 l( a5 C! m/ X2 j 如果网络联通的话,测试成功将如下如下的画面,如图:' O4 }0 M( Q1 L) f7 ?$ X. y
3 _3 o2 _. Q5 J" A1 G: g0 W8 _& a* Z$ i }) M
: a9 d" ^# z5 l6 l$ m. |% n# y( v y. z- t/ \. `. O) `
6 p9 W3 m9 K4 `. T
& `* o+ |8 P" \" L* F& U9 G
|