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