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