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