1、UDP Client
- m. L' Q" {! W3 p2 m5 [! H1 S, D- /* # _! o, F9 _4 m) n- ^$ k
- * Copyright (c) 2006-2018, RT-Thread Development Team *
5 a. `* d# e2 m/ ~; q - * SPDX-License-Identifier: Apache-2.0 *
) X, z/ @8 s! Q& x - * Change Logs: * Date
" ^ @& g% ~7 `% O* b; ]% l - Author Notes * . N. G$ a4 d& V1 z: K$ W
- */
' c' w8 W3 ?2 y2 k, o - /*
$ j, ] @' x |7 F( }( }* U - * 程序清单:udp 客户端 *
! Y v; z) [- Y6 V# V - * 这是一个 udp 客户端的例程
; B z h' n. c2 S2 o% U9 K$ e - * 导出 udpclient 命令到控制终端 : g. ^7 P) T# _) Z) T, m
- * 命令调用格式:udpclient URL PORT [COUNT = 10]
0 Y4 ~8 u/ h9 q2 K) H, L1 [ - * URL:服务器地址 PORT:端口号 COUNT:可选参数 默认为 10 ' \$ Q* k9 N6 k; }7 V
- * 程序功能:发送 COUNT 条数据到服务远端7 d5 k8 \; s9 m" t
- */
. x1 E* y' G* r' O' l3 V5 N" M/ b - #include <rtthread.h>
6 E2 ~$ f' K8 q: w* A: E4 w% ?" U - #include <sys/socket.h> /* 使用BSD socket,需要包含sockets.h头文件 */
, x, l3 c4 Q0 d4 t- C a( y - #include <netdb.h>2 V3 y1 f7 w2 N
- #include <string.h>1 \! c" N* y4 B) o9 ]
- #include <finsh.h>
5 |, y# i5 m5 x9 J! r
# E5 ~" ^# D2 e- const char send_data[] = "This is UDP Client from RT-Thread.\n";- q( D1 N; v! `+ B* V+ L- k
- /* 发送用到的数据 *// b6 b1 g; I7 v0 F
- void udpclient(int argc, char **argv)* |4 n+ Z$ y$ _6 m
- {# C$ e6 n* u7 z! [8 X
- int sock, port, count;
b3 y4 t- R* J - struct hostent *host;0 O* v, ]- y/ G( h0 G
- struct sockaddr_in server_addr;
* l6 L9 C' d( O4 I5 X - const char *url;' ~7 y5 L/ M" B* e
- if (argc < 3)4 {# P: P% u* h6 g
- {
) F1 W& M- _+ U3 O7 I% j* { - rt_kprintf("Usage: udpclient URL PORT [COUNT = 10]\n");
% W" E7 d" K( W! g9 U - rt_kprintf("Like: tcpclient 192.168.1.9 8000\n");- i) z; ?: A5 l
- return ;
: J: U3 ^2 [# N- I+ o& a' g, E, G - }' r9 M, b4 G3 }2 P5 i- O$ |
- url = argv[1];) ~: b/ ]) ?- a' R
- port = strtoul(argv[2], 0, 10);2 I, ~! C/ C* I
- if (argc > 3)/ u. P @; d! c0 m6 u* C
- count = strtoul(argv[3], 0, 10);
6 T: {! u% \7 s: C/ [) J - else
- w( K4 H* R: m! r - count = 10;, M! W; E8 d9 o, e
- /* 通过函数入口参数url获得host地址(如果是域名,会做域名解析) */1 X# A0 G9 |# v5 M8 A% e* n& e
- host = (struct hostent *) gethostbyname(url);
8 t! ~# y4 H- e. t - /* 创建一个socket,类型是SOCK_DGRAM,UDP类型 */
, o6 M D: c$ A$ I: O1 } - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)# u8 x' t: H+ B# h1 N/ w; b
- {6 C% ~: m4 `4 W
- rt_kprintf("Socket error\n");
/ q( z- l/ t! f5 d) n% s' Z8 m - return;0 g# J& Y% ?1 g4 d) s
- }" v7 @9 a& l5 h% Z) I
- /* 初始化预连接的服务端地址 */
) J9 n/ K ^4 C1 c) t8 F" @$ A6 L1 U& @ - server_addr.sin_family = AF_INET;
) \ n: i# f/ s9 t4 `0 J# @ - server_addr.sin_port = htons(port);) O: a# J, y4 ]/ K( N$ F( Q) d. z/ d
- server_addr.sin_addr = *((struct in_addr *)host->h_addr);+ Z ~8 j5 L/ b5 r h3 e$ ^; d" O
- rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));/ s0 N, T! E" Z1 J4 b+ t
- /* 总计发送count次数据 */
2 {& D8 H- Y, l5 Q8 F - while (count)
8 }- l$ A3 a1 w( h3 b - {! c1 x% n6 o& J' m6 W
- /* 发送数据到服务远端 */( g$ s- }9 Y1 e' y3 k( e
- sendto(sock, send_data, strlen(send_data), 0, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
+ L3 {5 w% y0 V' G8 q7 v, j' o - /* 线程休眠一段时间 */$ F5 |# R% i' S! r- L0 U
- rt_thread_delay(50);7 M0 Z8 C3 X" P' d
- /* 计数值减一 */
/ r+ L9 A6 w' k6 K% m( c, Z - count --;
- b3 ]5 E! G6 q, S - }
( A3 g% }' s, C" r! s - /* 关闭这个socket */
3 o$ W7 V( ~3 L% F: o2 v - closesocket(sock);
% n2 y$ {1 K+ Y4 j, j2 N - }+ E N$ @9 A0 |; t' U
- MSH_CMD_EXPORT(udpclient, a udp client sample);+ d/ v3 G8 J- o5 w2 Z3 E) I$ M
: C3 o/ }$ u& v" Y' R9 `
复制代码 2、UDP Server
) V' J0 @, J# }, B( x' F- #include <rtthread.h>( O7 F8 a1 @, i0 U
- #include <sys/socket.h>, W) |$ c. Z6 ~* C/ F6 y
- /* 使用BSD socket,需要包含socket.h头文件 */
; O* V0 u4 A! X' f - #include <netdb.h>, z( ^5 s9 Z0 s0 @+ o1 X7 k
- #include <string.h>; z/ v& o% g3 E, H
- #include <finsh.h>: s9 x% p- \! O
- #define BUFSZ 1024
+ w* h8 W _4 P - static void udpserv(int argc, char **argv)
; k7 J8 E+ F4 @; h: y, S: @ - {" T* D: d; p4 |( }- R0 ^: s
- int sock;
& I Q; Y8 n2 E( h1 d5 z - int bytes_read;( P- h5 q0 g9 i0 T v5 C' D( H% t
- char *recv_data; [. C3 ~) u1 ~- h4 G3 }
- socklen_t addr_len;. m/ x7 i: W- Z
- struct sockaddr_in server_addr, client_addr;& a/ |* K6 q8 s9 O
- /* 分配接收用的数据缓冲 */
5 ]( U* @5 M _) m5 I# H0 f - recv_data = rt_malloc(BUFSZ);
9 r3 Z. S2 {9 A( |( s/ P - if (recv_data == RT_NULL)% G) U* g; R' B. L
- {1 @1 s. T: p: A+ c8 O+ u
- /* 分配内存失败,返回 */ $ v# `: f6 l z) i( z C7 g6 e
- rt_kprintf("No memory\n");8 J( y( k/ F$ x1 ^# P
- return;- o5 O) _) ?$ s* F+ T7 n6 _, x
- }) I6 Q" D; ^0 o, ~! B9 l
- /* 创建一个socket,类型是SOCK_DGRAM,UDP类型 */
8 Q6 B, D+ z7 l2 M - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)6 g( s2 F" N4 Q6 V" m, {
- {$ E! r5 _' \* {. i7 V" m
- rt_kprintf("Socket error\n");+ m z( x) S2 [, U1 ~/ f+ T- s
- /* 释放接收用的数据缓冲 */
# q& z( O8 y- e/ J7 _ - rt_free(recv_data);$ v( X) }: q' n# f% C
- return;
$ B) Z! m$ j i5 p. ]2 ? - }
* a# @$ y) d8 L6 {6 g7 m - /* 初始化服务端地址 */) D: q- D8 }8 f' T% n' |: I- f* Z
- server_addr.sin_family = AF_INET;
5 { w; W* Q) s' Z - server_addr.sin_port = htons(5000);( w: O; V, {( i# z" f" ` a
- server_addr.sin_addr.s_addr = INADDR_ANY;) M2 u2 _( _3 f$ J+ p& f6 ]
- rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
- ~9 |9 `9 H8 J) d- B - /* 绑定socket到服务端地址 */' |) j8 ]0 t7 t! E' A3 t
- if(bind(sock, (struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == -1)
7 n* \- `3 }; j( i- ] - {* ?/ o I! e. g
- /* 绑定地址失败 */: \7 F( H6 k% b. y9 p& H
- rt_kprintf("Bind error\n");8 {* F0 r/ z0 Y& E- l0 {
- /* 释放接收用的数据缓冲 */
; g9 ^* {* r, C - rt_free(recv_data);# }/ G' e- w' E% I1 E2 a$ c
- return; r: D2 T0 e. U( Y% S% x1 ~0 S
- }
6 A$ I; A' {. n1 K' z - addr_len = sizeof(struct sockaddr);6 `2 [. h: j. `+ T1 o6 o
- rt_kprintf("UDPServer Waiting for client on port 5000...\n");
1 ?# C5 X3 k' R2 x* `# V+ I - while (1). H, e- g3 u8 _/ w
- {
2 z3 p; J# g. z/ s$ \, z - /* 从sock中收取最大BUFSZ - 1字节数据 */. D/ C0 L2 {3 h, Y+ i
# I& o% x0 B- g- l w$ h* {- bytes_read = recvfrom(sock, recv_data, BUFSZ - 1, 0,
$ V3 M8 ]# e/ u: Y/ e# O - (struct sockaddr *)&client_addr, &addr_len);7 B. k4 Y( j6 \+ ?4 f' [
- /* UDP不同于TCP,它基本不会出现收取的数据失败的情况,除非设置了超时等待 */
- h# ]# X. i: x8 H4 Y8 |) H - recv_data[bytes_read] = '\0'; /* 把末端清零 */
7 [5 t8 _9 k$ @# j - /* 输出接收的数据 */2 `, I5 N( L& j6 N7 n* [0 e6 C
- rt_kprintf("\n(%s , %d) said : ", inet_ntoa(client_addr.sin_addr),8 {; I4 r2 J& s
- ntohs(client_addr.sin_port));, a/ |* T& w% U& U1 Q0 a7 B8 a
- rt_kprintf("%s \n", recv_data);8 N& Y5 P# p. z6 D7 V4 d# }
- //udp 用 sendto 函数发送. L5 O2 e1 E# z" n X% `
- sendto(sock,recv_data,bytes_read,0,(struct sockaddr *)&client_addr,addr_len);1 z5 w/ v/ r" X) ` G
- /* 如果接收数据是exit,退出 */ 4 n' ]4 C! T7 W: M. v3 A
- if (strcmp(recv_data, "exit") == 0)
9 D) V% I ~' ] - {& L6 G% z! \) X4 u6 e; o9 I4 N( y
- closesocket(sock); /* 释放接收用的数据缓冲 */
! Q, z% |& C! I( {, b9 q - rt_free(recv_data);, d" R9 x! Y8 Y' s/ Z
- break;& \- ?, g& r4 E5 j
- }
; m! x2 E5 _" C! p2 o7 G5 A - }
0 V& Z% T3 v( ?; T - return;
6 z8 ?( g% {9 ^1 Y9 I) Z - }
( ^2 [, r$ j/ @* J. P( Y
( O6 {& {* c; L' O: \- MSH_CMD_EXPORT(udpserv, a udp server sample);6 d9 z+ f- u% F
复制代码 3、TCP Client8 u# U. F0 y/ ?/ Q
- /*
V& d+ @- K0 j, F - * Copyright (c) 2006-2018, RT-Thread Development Team
3 \, o! }1 L) D) [: M - *. z' W( o; Q) X7 K3 G) f9 Y" y( h
- * SPDX-License-Identifier: Apache-2.0 *4 @: w9 O+ L; r2 c: k9 t/ k
- * Change Logs:
% t6 B" A6 h: e3 \( C - * Date Author Notes *
9 A) z6 }; Y3 o% T - */5 s9 a& J, M! ? w$ R* r3 T
- /*
. c' d5 q3 \$ U0 Q6 U9 g: V - * 程序清单:tcp 客户端
7 i7 m; k- N" d4 }/ c, M - *' w7 i: w+ w9 a/ D x S+ Q. F2 k6 j
- * 这是一个 tcp 客户端的例程- D$ L2 M5 x* H5 s& ?9 k
- * 导出 tcpclient 命令到控制终端
7 T: i! j8 O- N' F2 O7 H2 n - * 命令调用格式:tcpclient URL PORT3 q( c$ F5 [! P
- * URL:服务器地址 PORT::端口号
* Y9 ]( ]0 h, D [ - * 程序功能:接收并显示从服务端发送过来的信息,接收到开头是 'q' 或 'Q' 的信息退出程序# k h# U" j% o" Z' w; }( S2 S
- */3 r# a" J: c6 |) F0 S$ B4 Z# M
- #include <rtthread.h>1 ^# o; f- F P4 q
- #include <sys/socket.h> `/ r9 c3 P% C( Z0 b+ y4 g
- /* 使用BSD socket,需要包含socket.h头文件 */5 A! g7 E% j0 B# Q7 j6 O i
- #include <netdb.h>) z4 _! u) {. k9 d, D' F6 @" _7 m# B
- #include <string.h>3 l6 n. P# [& |# [; D/ g6 ^, h
- #include <finsh.h>
& I# D; g+ s, [; m/ c - #define BUFSZ 1024( g5 A) K9 i+ Y9 J7 r
- static, f6 S/ e+ i) k4 W* h6 B
- const char send_data[] = "This is TCP Client from RT-Thread.";
* J' B# @& W1 m# m - /* 发送用到的数据 */9 E9 }5 v; K* l0 f& J
- void tcpclient(int argc, char **argv)
$ b, @, @& c. E% H - {
- s( X' v$ c s0 N4 P, O - int ret;, e% ~1 ~' L: g( s/ W
- char *recv_data;9 d7 `5 ?- { y# m; j
- struct hostent *host;
Q% j. v8 X: Z& D - int sock, bytes_received;
1 K) V' d+ l7 q9 `5 S, {2 P - struct sockaddr_in server_addr;
0 z2 c# L6 _, W - const char *url;" c$ _, V# p) K, a. F0 l& l! j$ m
- int port;
2 s9 j9 h" e5 Z! D7 d - if (argc < 3)
$ O; q; p+ G6 i( t4 ^ - {; `! T+ [* V# E, y( T; u6 E
- rt_kprintf("Usage: tcpclient URL PORT\n");0 ^1 k2 n5 C4 j9 [: w$ x% @: B' y6 {
- rt_kprintf("Like: tcpclient 192.168.12.44 5000\n");* m1 \, M: d$ a, ~0 w0 y/ B9 H
- return ;- K: e S9 c& ~" P& a
- }" b% ]! A8 h) H4 M6 e, |
- url = argv[1];, G6 f/ P3 K0 E% d, x2 X$ z
- port = strtoul(argv[2], 0, 10);
, s( K7 `/ S* F0 v* V/ Q - /* 通过函数入口参数url获得host地址(如果是域名,会做域名解析) */: X# r- D) p ~6 Q# W
- host = gethostbyname(url);, M- S" [; n0 b' b- z0 E$ V
- /* 分配用于存放接收数据的缓冲 */ Q- g2 u+ M3 @& O9 P# q2 y# Q
- recv_data = rt_malloc(BUFSZ);# ?* W3 w* @9 K! m
- if (recv_data == RT_NULL); U1 [2 m6 B0 w' J6 W- A' Y0 x/ ?
- {
) j9 z, H5 n: V; x, E0 f# F* s' z - rt_kprintf("No memory\n");7 R% p5 S. k# T, |6 P' R
- return;. G) u7 p2 y+ _9 P! s6 }5 d
- }
5 ^/ v6 ?: t+ J0 a - /* 创建一个socket,类型是SOCKET_STREAM,TCP类型 */) S( B, [5 S% J7 d% V7 Y1 j
- if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
7 g$ |+ o U9 T - {% K! j* x9 M' g C6 u( i
- /* 创建socket失败 */% x' I: x. D) h8 M
- rt_kprintf("Socket error\n");
. I) r @( v8 b$ K - /* 释放接收缓冲 */% O. ]* J! E. H' w. c [
- rt_free(recv_data);
) E1 M# M+ Y! H4 T; [4 K - return;( f6 n+ e' {" G; |! U& T) d
- }2 Y& J F( `6 a7 W( ]
- /* 初始化预连接的服务端地址 */
6 x0 s( u" q6 D: ^" t/ d" Y2 U - server_addr.sin_family = AF_INET;. }5 A. n" A- Z1 r' \4 K6 o5 G
- server_addr.sin_port = htons(port);
: R n0 v+ ?& c0 j, f. N6 l8 f - server_addr.sin_addr = *((struct in_addr *)host->h_addr);
8 ?$ z8 }1 ?" e+ h - rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));. m3 B2 }5 t! T. P
- /* 连接到服务端 */, `% k$ p" u( w9 W# i W9 Q4 m: o
- if (connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)$ t* a8 Q& }* ~7 r g
- {4 y6 x9 n: f3 y5 O9 U8 I( ~
- /* 连接失败 */4 c2 c& b/ q1 B- [
- rt_kprintf("Connect fail!\n");
+ Y! ^ S1 @/ V8 F% c* [. ? |& f - closesocket(sock);
& b& b- b% }6 R4 q - /*释放接收缓冲 */* T/ Y7 _7 \4 f- g. y/ _7 R6 R) J( S
- rt_free(recv_data);
/ U2 A, Z( {; m% r - return;. D, L& V% S7 k( ]# N! w
- } b; D! T5 h( H1 m* l7 n% r' X
- while (1)
' G1 R' f% i( s: a - {- n( ~% R2 {& H2 h- j
- /* 从sock连接中接收最大BUFSZ - 1字节数据 */
% q p) V \5 { @ - bytes_received = recv(sock, recv_data, BUFSZ - 1, 0); Z1 [2 c, h: R: C4 O+ y- t
- if (bytes_received < 0)- F( Q y; V% l% T. D6 ~% ]1 R$ l
- {- }% o. m6 D+ g# D$ G$ o* R+ y( }
- /* 接收失败,关闭这个连接 */
8 u. W6 F" n0 y: T u3 A - closesocket(sock);9 @$ P0 z2 {% ~# J1 w7 J/ r$ m
- rt_kprintf("\nreceived error,close the socket.\r\n");# A* ~6 s+ m; f; @& [- a1 J" s
- /* 释放接收缓冲 */
7 T( B& D3 L2 z- ^0 x P - rt_free(recv_data);, ~, o5 ^3 o3 |$ W
- break;
# N& k6 V/ k* |* X( Y5 F - }
f, N; S+ H2 `% @% L - else if (bytes_received == 0)8 F) @( [/ p5 D7 ]5 p/ _
- {
" G" ?& w4 O) ^7 f - /* 默认 recv 为阻塞模式,此时收到0认为连接出错,关闭这个连接 */
. d1 b& M* ]3 ~ o - closesocket(sock);
2 d0 V J; j( d3 |- ~5 N0 F - rt_kprintf("\nreceived error,close the socket.\r\n");. a' V4 u7 T$ j/ E0 h- z; J+ m$ e
- /* 释放接收缓冲 */" z6 R3 o( y; l
- rt_free(recv_data);$ x. x$ Y/ l* C1 F5 r
- break;
+ p, w g! X3 C - }! P2 i! V, D4 C' r
- /* 有接收到数据,把末端清零 */
2 q& O- n1 c/ [. Z2 }8 F" Q. P3 K - recv_data[bytes_received] = '\0';
9 V' H. d$ o9 ^* Q" Q& V - if (strncmp(recv_data, "q", 1) == 0 || strncmp(recv_data, "Q", 1) == 0)
0 P# g" f) [3 H; [( v4 x - {
]+ @) u7 Q) x - /* 如果是首字母是q或Q,关闭这个连接 */3 M3 ^: _$ A: B/ k& w9 ]% U5 J
- closesocket(sock);* ]* M2 ~/ y$ }1 \0 H
- rt_kprintf("\n got a 'q' or 'Q',close the socket.\r\n");/ A4 h+ x6 ~3 B: D6 B) l! E# S
- /* 释放接收缓冲 */
4 u3 a! { a# e8 Y5 ? - rt_free(recv_data);: L# F1 j1 r8 F) {' M
- break;
: Q, ]. p0 E+ K% \" ]6 H - }/ g. g1 K' f) Z* q5 h) l$ D
- else7 Y$ D: t2 H/ |4 ~' C6 F) a8 Q3 f# p
- {$ F- U5 u6 E1 E5 R1 E m) `+ C6 B9 D
- /* 在控制终端显示收到的数据 */. S Z- g2 x3 [% w
- rt_kprintf("\nReceived data = %s ", recv_data);& w3 s! z5 u) H* D& W( B
- } /* 发送数据到sock连接 *// Y+ a0 Z7 E8 K5 F) \$ p9 Z( { H
- ret = send(sock, send_data, strlen(send_data), 0);- c* M. r9 o2 n1 {
- if (ret < 0)
& {. `/ t+ }6 `0 ] k6 m: s - {
8 `& t- p8 h% C* J, C. @ - /* 接收失败,关闭这个连接 */
3 C" r& x# M. E9 `- e - closesocket(sock);
9 t Z1 J& X/ _6 w( [( Y" H - rt_kprintf("\nsend error,close the socket.\r\n");3 D4 ^+ I2 C# e: X" F% K
- rt_free(recv_data);
7 t6 W( L8 `+ B6 m9 ` - break;
S0 g; A0 a: E* i0 t - } I$ T, k1 t1 N ^, E- z, {4 h8 L
- else if (ret == 0)
' Z% a4 i7 g8 l( M' \& [( _$ @ - {6 k: ~" M8 k0 m p, l& c$ z
- /* 打印send函数返回值为0的警告信息 */9 W6 A3 l5 S, f" `2 z- @& d% R
- rt_kprintf("\n Send warning,send function return 0.\r\n");6 \8 P2 e0 R5 a" ~
- }% i, T( U, X$ E" y
- }
+ ~4 x7 L$ w m" J. K( V9 s - return;
$ H9 f) o1 Q: f - }% Q# H. X' m r
- MSH_CMD_EXPORT(tcpclient, a tcp client sample);
t6 a9 a' O8 J* x4 E% y1 ~! X& `
复制代码 4、TCP server
3 r; q% A+ c2 V0 D1 ]8 ~7 W) P- /*. p9 _; U8 J, E4 `, G* H/ L+ n
- * Copyright (c) 2006-2018, RT-Thread Development Team' S0 H& A+ Q' A1 Y6 I
- *$ |+ ^3 [+ v `4 k6 `& ]- c
- * SPDX-License-Identifier: Apache-2.0
/ Q3 L ^: {0 }0 G& \ - *
i ^2 H6 X$ F0 M* ?: v - * Change Logs:
" C l3 h# r" Z1 Q% n+ t7 U - * Date Author Notes
$ e+ D u# @+ m. p3 l+ }" M - *8 T: D4 C& Q! {/ t9 q% h7 P: y
- */8 ^; B" d$ [4 \) U5 ]. o8 D% H
- /*
0 }! ]0 u& ^$ |; ?, h - * 程序清单:tcp 服务端
' ` K, l& M$ B* k1 B/ F+ [ - *) B' J0 y. M: t- K8 W
- * 这是一个 tcp 服务端的例程9 b+ X" U# P8 }0 o# y2 Y/ x4 p) Q
- * 导出 tcpserv 命令到控制终端' Q3 [4 @! G1 G/ @1 I2 D
- * 命令调用格式:tcpserv: C; A& e" k$ A7 n' P
- * 无参数; _. V3 ]$ h5 W0 M) ?* [( ]/ a6 b
- * 程序功能:作为一个服务端,接收并显示客户端发来的数据 ,接收到 exit 退出程序 ^. z7 |) p7 |; b( |+ K/ W
- */
( E/ z- M0 P0 A3 W' V% r, M - #include <rtthread.h>
7 D) Z* u4 H* A& Y8 x - #include <sys/socket.h>
0 s1 {/ M; ]% B' \$ R: ]# V - /* 使用BSD socket,需要包含socket.h头文件 */
) T9 K& K( Y! g - #include <netdb.h>
5 A- W! I+ G, p( x% @9 }' z- M - #include <string.h>0 h% u: V% P* o, ^+ @2 U4 L* b
- #include <finsh.h>
( c' T0 Z* |6 c W9 m# r; y - #define BUFSZ (1024)
* b. E: U M- Y; { - static const char send_data[] = "This is TCP Server from RT-Thread.";( T& _; {+ ?: y- P1 C. Y' n
- /* 发送用到的数据 */* l+ E+ N6 _2 L$ W8 _- s, C
- static void tcpserv(int argc, char **argv)
/ f. E8 r& {. E7 y4 Z - {
. I( u* V8 T6 H1 i6 d+ g# Q - char *recv_data;
1 `4 s: _7 [, x |& w9 g+ O - /* 用于接收的指针,后面会做一次动态分配以请求可用内存 */9 H1 X! m1 z6 K+ d! h+ t: j6 {
- socklen_t sin_size;
; w" K! @! o3 f& ^ - int sock, connected, bytes_received;, |7 u" o, p9 R; E. l
- struct sockaddr_in server_addr, client_addr;1 x2 s! m+ P' E- |/ L
- rt_bool_t stop = RT_FALSE;6 _! x9 s% }8 U& G$ W9 t$ \7 q
- /* 停止标志 */
9 L# @; G9 w4 X- s1 d - int ret;- t7 N- W' G9 e, T, k" Z# Q
- recv_data = rt_malloc(BUFSZ + 1);
, m0 a+ T+ y$ P - /* 分配接收用的数据缓冲 */
2 m# b. t( n2 {# x* C3 } - if (recv_data == RT_NULL)
8 g7 ^7 {4 N! Q- v+ g' D - {
5 m, {6 W1 v2 Y5 K1 o& O7 b( w; S - rt_kprintf("No memory\n");
% S% y+ g/ U* k* u" ` - return;, y- S( W5 w8 ?) r0 u; g
- }
% z7 F2 k ], \" w8 l. ~ - /* 一个socket在使用前,需要预先创建出来,指定SOCK_STREAM为TCP的socket */) z/ l/ {( G; J0 @5 }6 c
- if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)% q# \3 E" J0 p& ^
- {
8 A8 A! A% z# }( T: p; d) i - /* 创建失败的错误处理 */
2 @9 p1 S! k7 b - / l9 _3 c. b- e9 T
- rt_kprintf("Socket error\n");' m9 P+ C$ k: V) R+ L6 `, W
- /* 释放已分配的接收缓冲 */
2 z" E8 r: q% i! u - rt_free(recv_data);
" P' L1 v; R$ T) ^. i - return;
4 A7 A/ ^. E7 ~6 O: _9 k - }
# H0 L! x" i8 D - /* 初始化服务端地址 */' L9 r0 l! w" G8 q) ~* O
- server_addr.sin_family = AF_INET;
" ?1 \% A, m( X) l6 L' O8 b - server_addr.sin_port = htons(5000);7 J8 w2 U, B. y* X; k
- /* 服务端工作的端口 */
) j: r- _% s# X9 D - server_addr.sin_addr.s_addr = INADDR_ANY;
. [2 o2 N2 H0 N9 y' [7 a" \( C - rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));; P# v+ c( `. v% t" ~
- /* 绑定socket到服务端地址 */) r$ c9 @: s( `! Z1 M
- if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1). r3 k6 f* D. P1 q" t
- {
5 w3 \% v/ ^# i. X& C - /* 绑定失败 */6 F6 k) T. B* p( S3 N/ |
- rt_kprintf("Unable to bind\n");+ S/ O! l6 a3 a
- /* 释放已分配的接收缓冲 */: J/ k5 s5 R# d4 m+ E
- rt_free(recv_data);
3 X$ u7 ]( e: A- Z( L) b8 n - return;5 w( p5 G. z1 A5 F
- }' ~9 X/ d0 l' ?; [4 u6 ?; X% k
- /* 在socket上进行监听 */4 G% r- W) W/ v" c6 Q
- if (listen(sock, 5) == -1)
% K- K2 x+ G. L3 C% J7 y - {0 H4 O: Z- Z! s& |
- rt_kprintf("Listen error\n");
, U# k. K4 ~2 T" ~( u; q - /* release recv buffer */! B5 W* E% N w/ v |1 Z
- rt_free(recv_data);
|& a1 Q3 L) T4 M* L" b - return;
, H; `7 v- x. o; p - }" [8 R+ a/ }7 j9 n$ K
- rt_kprintf("\nTCPServer Waiting for client on port 5000...\n");, l+ X1 j b; v/ S0 r8 J
- while (stop != RT_TRUE)
# M8 a; W" w, h' @, D7 v - {
. a& D# ]1 z8 M1 H& Z) g& ^9 J - sin_size = sizeof(struct sockaddr_in);# P% z+ m2 ~ `2 ]
- /* 接受一个客户端连接socket的请求,这个函数调用是阻塞式的 */2 p% r# w+ Z# J3 ]1 U
- connected = accept(sock, (struct sockaddr *)&client_addr, &sin_size);( }% u! D$ m( u% J% O: _3 d3 }
- /* 返回的是连接成功的socket */8 T4 U/ N3 u: l. P1 K
- if (connected < 0). {2 @% n( U6 S+ y3 r( F5 b: b
- {9 c6 J/ o/ h& ^: \: S8 A& o
- rt_kprintf("accept connection failed! errno = %d\n", errno);
8 P3 H6 v- U/ H# P: s8 H - continue;3 T' c; M" t; G& A# f
- }/ x2 u* G8 _. V+ L, w. ?4 o- ^
- /* 接受返回的client_addr指向了客户端的地址信息 */! V( K4 h t1 `% Q& |
- rt_kprintf("I got a connection from (%s , %d)\n",9 C1 o5 l- }; |
- inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
4 D. H: L7 B% O$ y. r2 U9 |: ?+ n9 W6 h - /* 客户端连接的处理 */
# o. Y# a R/ D1 O - while (1)1 j8 b' {! H+ I8 D# b. T
- {
* D- v2 f' e0 v7 ~; y2 C9 @ - /* 发送数据到connected socket */
, K# x% f8 {+ A - ret = send(connected, send_data, strlen(send_data), 0);
5 x8 E& X% J& s1 r4 K8 ?$ U - if (ret < 0); @7 i4 s; `, @" o4 |6 o7 u
- {2 [7 }( ]' A9 f
- /* 发送失败,关闭这个连接 */& V1 A& |' E d2 ~* S
- closesocket(connected);% }/ @& N3 W6 m/ t% O
- rt_kprintf("\nsend error,close the socket.\r\n");0 \ o$ \! t, Q' H9 x! Z
- break;+ _5 j- t; k5 `2 O- y3 P
- }
; [/ N) Q! a" S - else if (ret == 0)( \$ q! y6 z5 `! M, o$ v
- {' P3 H7 K' S" q9 C$ ]$ X" N
- /* 打印send函数返回值为0的警告信息 */
) p. {; D, _# l k0 B2 h2 r - rt_kprintf("\n Send warning,send function return 0.\r\n");
# \3 ^* E, G5 S* m/ _- } - }
- q" T' ~4 @1 r4 j1 p - /* 从connected socket中接收数据,接收buffer是1024大小,但并不一定能够收到1024大小的数据 */
* q* {3 c' c! L( F4 g: t - bytes_received = recv(connected, recv_data, BUFSZ, 0);
. A" I# W/ j/ K6 R - if (bytes_received < 0)/ A7 t7 q+ @* q4 G+ ^
- {
0 o7 {2 ]2 N9 Y: u6 E - /* 接收失败,关闭这个connected socket */
Z1 ]0 S7 y, g7 Y* G1 Z) I - closesocket(connected);( x9 g- l4 H0 N1 e$ p7 W, z
- break;
: u2 X; d, m/ z/ `8 p, R - }
& l# I' @1 X0 b. Z6 {+ \ - else if (bytes_received == 0)' @+ ` {7 Q, ^6 n8 B
- {. \3 p( q) a4 d4 ~
- /* 打印recv函数返回值为0的警告信息 */+ q$ k+ r3 Z0 c( v& H2 `2 V
- rt_kprintf("\nReceived warning,recv function return 0.\r\n");
" r" Z% ^/ s Q* v - closesocket(connected);
) q! K! `( h" d, W - break;
6 l+ }+ ~, `8 x6 @! p* T/ x - }
5 b7 y* {2 U$ H0 C! `; g - /* 有接收到数据,把末端清零 */
7 F; x- ~# M' h! H& C - recv_data[bytes_received] = '\0';
/ |+ N5 l2 G9 W- l) E - if (strcmp(recv_data, "q") == 0 || strcmp(recv_data, "Q") == 0)
, b, @5 a# `, _+ Y* L% h - {
: [+ Z" R* e/ n/ ]' \ - /* 如果是首字母是q或Q,关闭这个连接 */, s3 T0 x7 d5 z! O o- v, q3 u
- 5 }8 u4 X% v+ O6 T. a9 |
- closesocket(connected);
3 g8 u$ h( Z$ b - break;
% O2 A6 G5 p1 ?% d" @- U - }
% W$ Y3 b& Y: s+ j4 d( C - else if (strcmp(recv_data, "exit") == 0)5 p! c( d+ r0 \1 n
- {
; n0 W5 t7 `. v - /* 如果接收的是exit,则关闭整个服务端 */+ V/ t/ ] x2 t, h# q( b
- closesocket(connected);
- j: z L$ m# c; y- e! }3 F - stop = RT_TRUE;
+ a! {6 p' B( \, N9 Z% M* U - break;
1 H' ?6 U; R' [% P; o - }
/ S4 |/ B4 N+ v) _! z - else
- @/ e: @6 ], [ r T - {
* D" p$ S5 A+ \. B b: c - /* 在控制终端显示收到的数据 */! N. A$ ]' K1 ?
- rt_kprintf("RECEIVED DATA = %s \n", recv_data);& N( Q# ]* U- ]* d) x! H- S& e
- }
3 t$ y" S/ ~* ^, W - }" }, B, D: ^$ ~; ]/ q3 r
- } /* 退出服务 */0 D- R# E; Y! N
- closesocket(sock);
1 h8 a3 Y& l- a+ Z- G) b( ] - /* 释放接收缓冲 */4 P& A n+ w4 R8 W# I2 U, m
- rt_free(recv_data);' |% I, i, N5 j. M5 |' D
3 G6 Z6 m- [$ _% S$ c9 j; Y- return ;7 T \' f# O' W/ C; T+ c
- }( e8 }0 z4 G2 ~
- MSH_CMD_EXPORT(tcpserv, a tcp server sample);
复制代码 6 d$ O2 M/ X: s8 P# l
/ \" s$ l4 K- }/ Y7 k6 t7 G9 V5 S搬运过来,给需要的朋友~
- q7 N {2 C+ b3 C |