|
//=====================================================================
5 l+ B" g$ U! A//TITLE:
3 Y) j$ D5 {2 k% r1 G$ [// STM32F2xx的tcp_echoserver例程解说
2 u8 o: E* T) v//AUTHOR:; f( y1 U3 v x. x
// norains
) v! Q) |$ g2 w- S+ \8 |/ c7 v% z//DATE:9 O7 h) a( H# d) K- A0 Z0 n y
// Monday 04-July-2011
# p9 u6 b: z0 g, j1 ?" V% I//Environment:2 t6 d* \- C: ^. ^& s7 ?8 R. f
// Keil MDK 4.2. ^9 g h) M/ O# X! i
// STM32F207 核心版; Q" s5 w/ _+ L' W+ U! L
//===================================================================== 最近拿到STM32F207的核心版,板载有网卡芯片,自然要拿过来捣鼓一番。而对于一个从未接触过网络的菜鸟来说,最好的入门方式就是揣测ST公司的例程,所以今天norains也不例外。那么我们就一起来看看这个官方的例程吧!
( j9 ~4 o4 ]( d5 p ST关于TCP的例程分为client和server,根据字面意思,可以知道tcp_echoserver例程是将STM32F2xx作为server来用。而例程的第一步呢,便是初始化,调用的是tcp_echoserver_init()函数。 在tcp_echoserver_init()函数里,主要做了这么几件事情:
. I6 q1 c$ M9 n8 a- R 1. 创建一个新的TCP协议控制块) W4 _6 W M$ C! r9 H. \7 U- z7 S+ R
2. 绑定地址和端口号(port)
8 j7 N& j5 v: V! J; o 3. 开始监听(listen)
) |- x3 w- ] O* @) g2 L1 o$ G: Q 4. 设置accept的回调函数 其完整代码如下: - void tcp_echoserver_init(void) 7 Z' @" B# W7 S
- {
, Z2 H( G! z+ C - //创建一个新的TCP控制块
4 l7 i* X/ L9 W2 m - tcp_echoserver_pcb = tcp_new();
0 i0 ~7 }9 Y+ l: w; n7 X: Q& ?: I - ; h) [. L' h' I: W
- if (tcp_echoserver_pcb != NULL)
! T) Q* l3 ]7 }" s - { ) `. X' N4 Z# F/ y* N5 c% K
- err_t err; * b* i5 A2 k! U h+ G6 v: U! P) V
-
4 D4 z- S: ]- y* P. ? - //绑定到端口7
+ Q/ u0 R5 F& U! b1 W$ C - err = tcp_bind(tcp_echoserver_pcb, IP_ADDR_ANY, 7);
/ g4 V5 o+ }) X3 i -
! X. E& f" g( J - if (err == ERR_OK)
2 v+ Y$ {" `6 ?! E# P q8 D* i; g - {
; d8 L. z8 m( W1 V - //开始监听
6 g- w* u) h+ j* T - tcp_echoserver_pcb = tcp_listen(tcp_echoserver_pcb);
+ b M9 H6 N' y5 E - % F; t, k G: E% f; O% S+ ^6 B* D
- //设置tcp_echoserver_accept为accept的回调函数 & L/ q) a3 J6 v: k0 v1 f; T/ [
- tcp_accept(tcp_echoserver_pcb, tcp_echoserver_accept);
) {/ L. d: X, E" k - } % v/ Y1 D4 Z4 ^+ J
- else 2 ]( _0 K8 ?3 m
- { 4 w. h/ E# i2 ]( X1 O, m1 A
- printf("Can not bind pcb\n"); //norains 2011-7-4 comment
' @, P- o$ T! s7 X7 T7 M/ Y, i - }
6 B; E' ^5 M4 m( ] - }
8 j g& ?% `% Q: A9 a: ^+ j) H" n2 e - else
7 P7 I# d8 T0 o- d8 \$ i - {
0 h" D4 G- a& p1 M% h, E; h, V - printf("Can not create new pcb\n"); //norains 2011-7-4 comment ! a/ _! h' n t6 J
- } * M5 [1 t( l& K- b: ^& @% M! O& Z7 b
- }
复制代码 当客户端开始连接之后,那么被设置的tcp_echoserver_accept()回调函数就会被调用。该函数主要是创建一个新的数据结构,并且将该数据结构传递给底层的TCP,最后分别是设置receive,error和poll这三个回调函数。
! A, J& n2 D; O+ U4 O) I
0 l3 M9 d2 u/ T2 n2 E ? tcp_echoserver_accept()代码如下所示: - static err_t tcp_echoserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err) 2 y: l% X: n" ~
- {
e2 W% j# O& H. G7 e# _: Y! O - err_t ret_err;
; J. G! F4 F2 ~" @- a( H' R' z - struct tcp_echoserver_struct *es; ( n, j0 ~* z8 I9 T* D% z
- 0 z# P$ R; M ~9 g9 V
- LWIP_UNUSED_ARG(arg);
/ p' X1 s9 N6 j) o0 m+ C9 f - LWIP_UNUSED_ARG(err);
; u" U9 B: G g$ u - / k; Y# }* G: N
- ///给新的连接设置优先级
3 C+ B9 A# _5 N) [ - tcp_setprio(newpcb, TCP_PRIO_MIN);
3 @" p2 u3 B- T0 @* f - " }5 ^' |* y; W% ?) ]3 D8 V6 Z( A
- //分配一个结构体空间以保持TCP的连接 2 S# M7 f8 \+ z. i3 @* b2 ~" @
- es = (struct tcp_echoserver_struct *)mem_malloc(sizeof(struct tcp_echoserver_struct));
/ V3 ?6 `1 t' ~* X' Q- v' q6 @ - if (es != NULL) , e% r. T6 O4 Q
- { ) X q0 j2 S) K
- es->state = ES_ACCEPTED;
. O/ k0 L: B, K8 y/ ~ - es->pcb = newpcb;
W5 x; t4 n$ N- Q V - es->p = NULL; 1 N; L8 N: V5 b) ?) _6 i/ ^" C
- # p2 y( K& _- N$ o8 T. S" P5 m
- //传递新分配的结构体数据给新的pcb ! C. G: w5 N# j" A' I
- tcp_arg(newpcb, es);
/ Z. G6 Q8 E1 W1 l& r - 6 h: q: @) o+ F% e4 \# R; z2 B+ O- h, s
- //为新的连接设置receive回调函数
: m( p2 P1 w: ]% A - tcp_recv(newpcb, tcp_echoserver_recv); % e& l$ c" N$ v( j, ]
-
# D" f+ H0 l) D. N. t' o; g- b - //为新的连接设置error回调函数 3 K7 N; \+ ?: G. O
- tcp_err(newpcb, tcp_echoserver_error);
$ [6 w; b8 t. a4 I/ }# L# c -
' N8 ~* W% Y% D' p5 f8 ~1 h, b5 U* ` - //为新的连接设置poll回调函数
9 I2 x) j3 W: i" s2 ]4 b; T: y. _ - tcp_poll(newpcb, tcp_echoserver_poll, 1); + w. ~& {' Z ?, [) e
- 1 ]' S9 ^8 P- K4 @! U8 C o; G
- ret_err = ERR_OK; : d) I3 Y" G# A4 c
- } - w6 H! ~3 G ]3 [0 g# G* @
- else
+ ]9 B; [+ _3 l8 U/ x - {
. S- x1 k0 V% p: f( i9 d* G6 b - /* return memory error */
) s G Q! F% E3 A6 _1 U - ret_err = ERR_MEM; 1 H! A& a/ X6 o, ~! ]' J e
- } ! C! u3 L, W8 z
- return ret_err; ) Y! c3 A0 h2 Q2 E
- }
复制代码 接下来便是tcp_echoserver_recv()这个回调函数,因为该函数比较大,这里就不再全部罗列代码了。对于使用者来说,只需要知道相应的判定条件来代表什么意思就足够了,如:
, }$ z3 m% O/ h# O; |. T - static err_t tcp_echoserver_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) / d; o; p7 [2 Z9 p9 l, I4 u& t! M" T
- {
6 J8 C; |# p$ G5 g - struct tcp_echoserver_struct *es;
4 K& Y# Y2 V* D - err_t ret_err; 2 R1 ]* O% N# M& `& ^
- 2 l) y2 D: J4 C B1 h8 q
- LWIP_ASSERT("arg != NULL",arg != NULL);
7 ]# u1 D. z- E( [& C4 k+ R - - x0 V: z9 N3 l* k+ f. Y3 b
- es = (struct tcp_echoserver_struct *)arg;
* `; r; S; O4 D( L7 O- f+ a0 g -
- _0 }# g: J5 ?0 u) ?2 M' J - if (p == NULL)
: `' \2 V' g5 o M - {
7 E% l |. O [: {$ j" f. ^; q$ F! u2 x6 _ - //如果接收到空的帧,则释放连接 0 v# x* V9 i; F
- ...
& k: ?" n" R: G+ m+ K - }
/ w+ D/ P! Y$ w# N+ Y - else if(err != ERR_OK)
; H7 U# b$ d5 u& h/ M' K4 C! L - { 2 A# p2 d% j3 B) r7 M4 W# _
- //接收到一个非空的帧,但可能某些原因出错,导致返回值不为ERR_OK,故在此释放缓存
0 S2 o. ^. s% |$ M' O - ...
9 |7 V' m3 |5 ], V - }
5 \' }( K& J4 @# g2 j4 ^6 ` - else if(es->state == ES_ACCEPTED)
- o% }) r- U; f y - { 9 A/ u, o! t) g
- //连接成功,在这里需要设置sent回调函数
3 J- `8 Z n$ a6 K# E0 ^& [) C - ... $ V% {7 f7 [" E) T. e
- }
0 G6 C% {/ z. i. F) e - else if (es->state == ES_RECEIVED)
1 x' u+ |, \4 B$ D% V% z" F - {
- V& |/ [) U/ @2 C - //从客户端收到数据 3 E+ T$ V* e. W. @( l
- ...
) D. o/ u, X; `% B/ p9 F - } # C/ i$ [' {9 d, }' |9 a
- else " J5 Q/ S: G# A% T# r
- { 0 n- ] w9 `" |) e8 V; K" |0 _) `
- //当连接关闭时,还收到了数据 " W: _6 u O! A+ c5 g
- ...
9 A8 v* |- ^; [& V, q - 0 y9 ^. W1 @5 T4 o$ \
- }
- U3 U7 a% ?1 q -
$ G7 {' P, K+ g2 p7 v1 w2 D - return ret_err;
! {/ L& S7 `" _ - }
复制代码 STM32F207的代码部分就暂时说到这里,现在的问题是,如何 测试这代码的正确性呢?这就必须用到ST提供的echotool.exe程序了。该程序位于stm32f2x7_eth_lwip的PC_Software文件夹中。该程序必须在命令行打开,其大致参数如下所示:
7 j/ ~& Y! ]8 v/ h; Y* i) M# S1 O% b: E: R: ~5 n& N( k3 \) ^
+ z6 u7 w2 [8 C- w* D% R9 V: d! H) w
如果我们的serverip地址为192.168.0.8,那么可以输入如下命令进行测试:
" ?+ }3 p* t6 c echotool.exe 192.168.0.8 /p tcp /r 7 /n 15 /t 2 /d Testing LwIP TCP echo server
0 f1 e0 f4 h5 H3 X5 Y) U; i4 y6 [ ; ^3 k& \: E2 X0 x& l
如果网络联通的话,测试成功将如下如下的画面,如图:& O; V6 x5 U4 H
( @* G i2 z4 [% N, ^0 j; D3 ]7 C& J3 q* B+ Y6 k) P
$ c- |% I- ^% ~( F" `7 h
3 d! F* E& r% V0 ^) J1 t# x
. g- E# [" v$ X- }; K* c0 n# Q0 x& g& J+ Y' D) V% F
|