//=====================================================================
8 Y& M \" u$ x//TITLE:
& ~! [! v. ?/ P Z& r// STM32F2xx的tcp_echoserver例程解说6 `8 w7 J W1 X
//AUTHOR:8 E% p+ ?2 h! ^) Z3 y
// norains: @- o a9 A p x, ]
//DATE:2 z" Z3 D, _# |/ K6 L4 J) c; Q
// Monday 04-July-2011
9 _' j# H! [* u! N2 [//Environment:
; k5 g) u/ {/ g% C' `// Keil MDK 4.2' Y4 G/ U P+ W1 i `0 H
// STM32F207 核心版
. Z/ v$ Y4 [6 u% z//===================================================================== 最近拿到STM32F207的核心版,板载有网卡芯片,自然要拿过来捣鼓一番。而对于一个从未接触过网络的菜鸟来说,最好的入门方式就是揣测ST公司的例程,所以今天norains也不例外。那么我们就一起来看看这个官方的例程吧! # Q C W n3 E4 a8 v. a
ST关于TCP的例程分为client和server,根据字面意思,可以知道tcp_echoserver例程是将STM32F2xx作为server来用。而例程的第一步呢,便是初始化,调用的是tcp_echoserver_init()函数。 在tcp_echoserver_init()函数里,主要做了这么几件事情:, m3 t3 ?. t+ g: |" k
1. 创建一个新的TCP协议控制块
4 [+ b% w" J8 F; G I 2. 绑定地址和端口号(port)& N2 L" i0 y: R. J A; Y3 e- L
3. 开始监听(listen) D) ~+ D6 \% W9 r$ j3 R
4. 设置accept的回调函数 其完整代码如下: - void tcp_echoserver_init(void) 4 z0 \. J" ?0 n8 g3 D/ W
- {
( w# a5 O5 s2 E& b - //创建一个新的TCP控制块 / m3 m' y: J J! W# w+ J4 g
- tcp_echoserver_pcb = tcp_new();
9 R& [2 p; D; }4 y - 2 V8 N& d- h1 ]3 B. a6 J
- if (tcp_echoserver_pcb != NULL)
/ f$ E1 m- ~. Y' d3 D" Q - { / J5 `! X* v9 s3 N& \6 ~
- err_t err;
8 F0 g$ }# F% Z7 A6 E* i- Y - # d* U6 {; P7 f* B
- //绑定到端口7
8 N0 J" o& T6 d1 U - err = tcp_bind(tcp_echoserver_pcb, IP_ADDR_ANY, 7);
! \, r- ^* b5 P - , x) h: z0 E) {. A
- if (err == ERR_OK)
: z5 v+ y' ^' L7 V* h O" `& m - { # b# S" ?* ~/ k1 @- u4 y9 l
- //开始监听
8 m [/ u* _. C- ~/ z( J% x - tcp_echoserver_pcb = tcp_listen(tcp_echoserver_pcb); 2 t6 p! o: U h2 S
-
5 S3 h1 v0 X5 `4 L! }3 \: i/ N - //设置tcp_echoserver_accept为accept的回调函数 ; g" n, w. a A* v I; O5 T* F
- tcp_accept(tcp_echoserver_pcb, tcp_echoserver_accept);
6 f9 X) N `% k - } 4 U( U& w2 U8 }$ I
- else 2 D+ Z$ Z: \$ r8 t9 O0 J# C" x
- { 7 n5 _8 v/ c/ k2 D' \1 F$ B6 b
- printf("Can not bind pcb\n"); //norains 2011-7-4 comment 4 x, t" T/ K% l5 Q
- } / c& n, s+ o1 K4 H
- }
H! ?' ?/ L* z1 V9 S# P6 D - else 5 \6 g, L7 p( p, x4 t' l1 D
- {
% I# R( F6 e8 b- n* t - printf("Can not create new pcb\n"); //norains 2011-7-4 comment
. W7 X* u* O' X6 W - }
: l3 l0 H: Y* G - }
复制代码 当客户端开始连接之后,那么被设置的tcp_echoserver_accept()回调函数就会被调用。该函数主要是创建一个新的数据结构,并且将该数据结构传递给底层的TCP,最后分别是设置receive,error和poll这三个回调函数。+ G% U. A4 |; q8 J- Z
6 e- }0 S$ t2 R0 G$ n2 {: J
tcp_echoserver_accept()代码如下所示: - static err_t tcp_echoserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
$ @; S2 `9 {6 Z/ O) w2 B& p: Z3 n1 K - {
) b# T0 Z P9 [' N! G - err_t ret_err; + K" w' v; Q- T$ c$ [. ?$ |
- struct tcp_echoserver_struct *es;
) J1 K2 t- R6 Z3 ~ - ' L. }8 H' F ]* ^. R: [: z
- LWIP_UNUSED_ARG(arg);
" o0 @0 R. F6 p7 ^; ]/ b) H - LWIP_UNUSED_ARG(err);
; h4 T) c: s D& S$ f -
2 ?1 L( j! T8 m$ V - ///给新的连接设置优先级
* P. t( [3 u: S7 [; e - tcp_setprio(newpcb, TCP_PRIO_MIN);
$ _6 v) ]* p$ ^, q O$ L - 8 [: F! ?0 ?* O: i+ G
- //分配一个结构体空间以保持TCP的连接 8 i2 W8 H* x$ ~6 V
- es = (struct tcp_echoserver_struct *)mem_malloc(sizeof(struct tcp_echoserver_struct)); : e* ]/ { L( E3 C4 g/ X, {
- if (es != NULL) ) ^: e; h8 V1 w, {0 j9 [
- {
+ c( E1 {. a' R: ?( S - es->state = ES_ACCEPTED;
. s4 Q2 n& Q- B i3 O8 p% P3 M' I - es->pcb = newpcb;
+ t# I* y( C. P' Q2 F( B" ^5 j - es->p = NULL; # ]4 k- _* @1 G$ O& h- U/ M
-
) i0 W$ m0 z2 r; R0 |+ n - //传递新分配的结构体数据给新的pcb : c& s% K7 [5 G% H$ I4 \
- tcp_arg(newpcb, es);
/ k' L0 t/ C9 M2 X2 u* R2 N - $ s9 u N0 v3 d: r# W$ o* m
- //为新的连接设置receive回调函数
0 s1 p7 D, V" z+ L& ]' r& c - tcp_recv(newpcb, tcp_echoserver_recv); 4 ] t, A0 Q* b& U# Y% v* L
-
% x% J! ~1 o7 c! @; O2 O - //为新的连接设置error回调函数 $ x4 g/ J5 F! {# P% f" T% \$ D
- tcp_err(newpcb, tcp_echoserver_error); 8 e6 V' A& u9 f; ]8 q" y9 k
- q* T8 k6 x& ~1 m! F
- //为新的连接设置poll回调函数 9 |/ s5 t1 o7 s2 {: `# t! P! @6 a
- tcp_poll(newpcb, tcp_echoserver_poll, 1); 0 x! @- w3 O. N% c9 S% s. c& S" x# T
-
4 H9 Y* \& V3 q) Q7 y% N - ret_err = ERR_OK;
3 p. @# X& E: z& `' g5 a6 s) u! q - }
) D- ]) T- J% ~2 E$ ]( e( I - else * d( i/ K$ g& \/ i$ v
- { $ |$ l0 I! Y( T9 V# N- V
- /* return memory error */
" x# k' f4 s# Q( e! H u - ret_err = ERR_MEM; 4 W+ {% q( e. g6 ^ T. w3 Q
- }
E5 J: {0 v: ?! U* u5 N$ P: Q - return ret_err;
: X8 F5 ]6 k; B D% p9 M0 S - }
复制代码 接下来便是tcp_echoserver_recv()这个回调函数,因为该函数比较大,这里就不再全部罗列代码了。对于使用者来说,只需要知道相应的判定条件来代表什么意思就足够了,如:
" b; B" a) i8 [9 E0 A' T, R5 { - static err_t tcp_echoserver_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
% l7 Z0 k5 o% n, ^3 c - { / c# e: v3 L; l( ?
- struct tcp_echoserver_struct *es; 6 R1 W$ |8 E( s* `$ q3 O3 W3 C
- err_t ret_err; , g" k& r3 d. K. h/ j- M" ~
-
' D5 ^3 z) [5 A9 i$ k - LWIP_ASSERT("arg != NULL",arg != NULL); ! `2 u' A0 d P! s. M$ g7 J
-
$ L% L0 l) e/ ]6 N8 s% C - es = (struct tcp_echoserver_struct *)arg;
3 C# Z6 I. ]3 X } - - B* f# K3 c% H, h
- if (p == NULL) 3 N; j! O( R0 o; ~4 k! p8 p( D: Q/ t2 K
- { 7 ? Z5 g) M8 ^7 x# m$ Z% v# h( D
- //如果接收到空的帧,则释放连接
k/ n, u& A/ U, t. @ - ... 7 }2 _! v* d0 `0 p4 D9 Q7 O
- }
; R9 S) M3 z& F. R! B# z - else if(err != ERR_OK) ! {6 {; _8 P4 x/ X/ o
- {
# n" V1 N& ^) R6 X* V+ e - //接收到一个非空的帧,但可能某些原因出错,导致返回值不为ERR_OK,故在此释放缓存
* e# u( @) |" G/ { - ... ! s) B$ n, S7 |2 H, O* a
- } 9 x$ J2 u# u0 L
- else if(es->state == ES_ACCEPTED) & s: `9 Z. e7 _ t( T
- {
& p$ F& |$ S( I$ y- l; p" }! H - //连接成功,在这里需要设置sent回调函数 # s, A* J3 d) Y/ Q P; x
- ... 0 y' k$ J) Q( m, W& d
- }
$ W: c% ~: F! v - else if (es->state == ES_RECEIVED)
9 L: y, i/ A- M$ S - { Q; w& g9 n* k/ e% G! f2 A0 N" \- k; p0 d
- //从客户端收到数据 % `- g u: x1 C3 g- @
- ...
7 M! D- Y' g0 R) @ - } - F2 H& V8 ^# _
- else
k. D9 G* D- P; Z3 I: C$ s - {
- l7 G2 _0 {5 K/ B* V - //当连接关闭时,还收到了数据
& B! S3 B3 \% r! [' R3 k) G! x6 X2 l - ...
7 u2 A H J6 l: ~ -
. p, ?2 g% `2 f - }
6 c) @2 z: u6 U* E2 H - 7 w1 G3 [0 T& h" s3 c: x
- return ret_err;
2 N1 c: k+ q- Q: B4 Z6 u, k0 ^ - }
复制代码 STM32F207的代码部分就暂时说到这里,现在的问题是,如何 测试这代码的正确性呢?这就必须用到ST提供的echotool.exe程序了。该程序位于stm32f2x7_eth_lwip的PC_Software文件夹中。该程序必须在命令行打开,其大致参数如下所示:2 P" q) U0 V/ T$ |! g0 `
: s5 H, f1 |6 R& @8 m/ Y
& u9 O6 D/ F& t7 u r. h/ g( o- `4 _- S
如果我们的serverip地址为192.168.0.8,那么可以输入如下命令进行测试:0 q* _: w: W c
echotool.exe 192.168.0.8 /p tcp /r 7 /n 15 /t 2 /d Testing LwIP TCP echo server
2 O1 Z8 G- x3 |, [+ C # w5 R: N) Y+ @ t1 C
如果网络联通的话,测试成功将如下如下的画面,如图:
8 y5 K' t7 E4 j" t; b
# G( ], j! i. F
- P6 L. a' X! j/ q% x' u( M" Z7 F6 {5 j8 Y" n! }2 j
: b- M; ~* k% Y4 ?, c0 ^" w$ v- ` z* F' @- x1 X
! h4 J( d/ \4 o: g9 L
|