|
|
C语言实现TCP-IP协议服务器与客户端互相发送数据的socket编程' G% P) t+ X" v4 I9 @
9 L1 @: H; G q# C* e; f
linux下用C语言实现TCP/IP服务器与客户端互相发送数据的socket编程: I1 @/ l1 O+ j, H8 Y6 M
' u. Y+ P1 }5 B
server.c! U% v3 X4 B& w- u
#include <sys/stat.h>) D7 C# Z3 E2 H
8 }- Y4 F. Q! d) }#include <fcntl.h>
* U, r; x+ S. S* c% ?+ d. P5 t; X4 ?- |" V. l3 K; ^2 E: ]* [; U
#include <errno.h>
% }& z8 _* U' E4 i3 l) t
L' O) u7 ]* p! E Q" z9 o#include <netdb.h>( _' b3 g: \! i. g( e3 F. ?
/ W& M* A. e9 V4 w8 e5 y
#include <sys/types.h>) H# }6 v* @. I" P9 v7 _
7 s1 b( k) i$ b7 ]# F#include <sys/socket.h>
" [; _& b h @3 w- p9 ~ [0 Z: ]
0 b& j. v2 g' _5 g: r, k4 _#include <netinet/in.h>
7 a0 A. G. T" ]$ a+ i8 A; o( h( Q3 h5 l/ k8 C# I1 F
#include <arpa/inet.h>5 W; [+ Y( b& _3 m
3 C5 l; Y: W3 @( g# L' q6 x$ j#include <stdio.h>' L3 G( i2 U0 G' m) F9 q
$ ^% _7 `8 J% v; u#include <string.h>) |6 X$ O# Y8 }/ K# X5 p+ V3 e* B
- h5 s$ \. s" N- F#include <stdlib.h>
. j, R; n3 ]% p; @4 ~' j3 b7 A/ i
0 G4 X# k* O: o% s, i#include <unistd.h>
( v3 d5 b/ C. K! N) V9 [& o6 I
! d6 ?( T, g: H# G9 e- {#define SERVER_PORT 6666
6 p8 t! G' ~4 @
5 ~$ d. w" @1 S& p$ N& {+ T/*
) `0 U# e! u6 @0 z监听后,一直处于accept阻塞状态,
: }2 t# p g# T$ B; I! |# U+ d6 d直到有客户端连接,) J& U* L; Q6 |- H& r
当客户端如数quit后,断开与客户端的连接8 ~& L# A% G! U! R
*/# q0 b4 h2 |5 F' A6 A
# i( l3 u; S7 Rint main()
; w! b( v3 B! n" \) P" a8 ~ D
7 i" `4 ~" T* T9 e# l{, Q2 v1 Q- p6 \" T# t, O( L/ ~
8 T a9 }1 J& H8 q) ~, ~/ B
//调用socket函数返回的文件描述符4 S7 ]+ F8 l2 _
+ J' e) ]% Y; Y0 n3 nint serverSocket;+ ]& [, F# F- ` O2 ]& f! V- m
* a1 G8 T# t! _; N, E$ r//声明两个套接字sockaddr_in结构体变量,分别表示客户端和服务器
7 A, r0 z# s6 J2 e3 }5 j5 m) q
6 h, ?" [7 a: y/ D: y+ fstruct sockaddr_in server_addr;
* d, @# g2 n! g( {" @+ V
4 d2 [: y/ F9 _; |struct sockaddr_in clientAddr;: p+ O, z7 f4 X) O* r' ?% r, {
9 l# v' L( v3 X: o+ Rint addr_len = sizeof(clientAddr);
4 |+ S* C$ l7 M' q5 T8 V
! f# r# w7 d2 d* i. o; j/ Mint client;
, C" m: E! I( {. t) [: \% K- A5 R3 J2 t2 g
char buffer[200];
3 s" o4 I( g2 i& E
& N% A5 v) b0 O nint iDataNum;" R5 Q* R4 u" `% r$ ^- F: A
0 h1 D1 j. h! S//socket函数,失败返回-1' z Q5 V: |" Y
+ `' D2 ?2 x1 ~& f1 h//int socket(int domain, int type, int protocol);
9 q% w% B- E" X' @) P% S! L" I" m0 a& `0 s
//第一个参数表示使用的地址类型,一般都是ipv4,AF_INET
, \6 `2 [& ~ z( s- p' w4 J1 i/ |& B" [) x& y
//第二个参数表示套接字类型:tcp:面向连接的稳定数据传输SOCK_STREAM
" {: p- u0 Z, D2 x* R( e! m* `7 n+ O% W2 [9 M# F
//第三个参数设置为0
/ l& Q. ~( o0 h3 m
8 J7 h# m3 r7 @' h h1 J/ ^+ iif((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)$ _( @8 N! e' S8 t" @2 u7 `) ]
' k/ |0 {" e; U2 u; {{# q$ j% q8 c& s. K5 K" T
8 n' n' M7 b0 Xperror("socket");
, p8 C# `" Y8 ]' E
9 a1 m& N8 C" ` U; ureturn 1;* ^# o4 i+ E) |. G3 C9 J
# V* T7 Q6 a# E$ H2 Q
}
7 }/ z i/ H: M
0 L# x7 y6 Y! V( _8 jbzero(&server_addr, sizeof(server_addr));
: W) b0 |7 U# q [: w: V9 o
6 r1 T/ ~" c9 q7 `3 K: i//初始化服务器端的套接字,并用htons和htonl将端口和地址转成网络字节序$ V0 |( \8 v9 @) W: r
* `' \& x2 R) g/ l# ~1 q
server_addr.sin_family = AF_INET;
! f/ S k. L' M! f6 g: X- c1 r; y; S
server_addr.sin_port = htons(SERVER_PORT);7 m- _' ^+ {2 D |$ a' I: j' `& v
/ g4 z+ j) a4 I& z* O$ ]
//ip可是是本服务器的ip,也可以用宏INADDR_ANY代替,代表0.0.0.0,表明所有地址- T) }5 z6 r4 D- m& q( C1 e) `: {! L
: H5 g2 j" K2 J) ]3 ?, m4 @4 fserver_addr.sin_addr.s_addr = htonl(INADDR_ANY);0 ^) R. ]2 [0 O3 v- k9 T
: u' o/ P% d: U//对于bind,accept之类的函数,里面套接字参数都是需要强制转换成(struct sockaddr *)
0 e( n- x7 W1 x
& L: W! I) k+ T- b% d! } T& [+ {: ^* g//bind三个参数:服务器端的套接字的文件描述符,3 @& @3 K7 X9 S, P7 t
! `, T/ Z- U0 ], o$ E7 r
if(bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)7 `2 Y5 D) }: n7 z; N. g, F9 D2 [
& Q. p0 o0 m# \8 I o* g3 ?{/ P; s5 g. [4 ~
) b2 y; b8 \. h& Vperror("connect");- O- j- Z4 q- g# B! @4 C
, ?: T8 b4 X* \ S- Xreturn 1;
8 x6 s5 x5 ^0 Z0 `* V4 ~9 ?+ d6 M" B3 \' ^, g" E0 [
}* x4 `" E4 i) L/ J6 B+ {4 _/ g1 {
1 q& u9 Q e7 n5 x' ?& }# ?& i
//设置服务器上的socket为监听状态5 T9 y! c/ {# r% D
1 a& @/ K7 K. M' Y9 x3 J* @/ y
if(listen(serverSocket, 5) < 0)
, u# O! G# V9 ]5 O+ h4 @; B' q( x+ T& R! \
{
* l' P% F/ B/ H; Y- t8 v) b6 B ]4 W+ f
perror("listen");
' I+ L+ S- P3 \8 S \
$ j7 j$ R3 b1 b' T- Qreturn 1;: v4 F7 v& |0 b/ Y2 z$ P2 `
& I0 c% f4 R, B( E( h}& x9 U" W. ^; H0 w" E* U& ?
: ? I0 q( L( x; E/ uwhile(1)
' G3 C% | N, T7 _, B. K
, P' M7 h9 \6 ^2 p9 p9 P{
- [* ?$ I% g9 @7 O% d8 e5 M9 I
6 v1 G0 @% p2 S. k. Z3 \2 |8 n; gprintf("监听端口: %d\n", SERVER_PORT);; T7 y# Z/ ~- d9 q
* N3 W4 z) c- y k4 T7 Q3 L//调用accept函数后,会进入阻塞状态- K! D% K b9 j7 _# ~# i
9 z7 X* c8 c4 |3 ?& V' g//accept返回一个套接字的文件描述符,这样服务器端便有两个套接字的文件描述符,
& ?: A8 T @ F; s x3 D$ g) j! L/ L$ m/ F
//serverSocket和client。
) l. h! W8 l4 l# w$ T& c) ?9 @8 i; Y2 I, s6 ~ E. J0 d
//serverSocket仍然继续在监听状态,client则负责接收和发送数据 c _. j3 g5 E8 F; s$ z
0 i; I" e# \' ~; P$ I' V+ Y
//clientAddr是一个传出参数,accept返回时,传出客户端的地址和端口号# d' \4 `4 Q& _8 T! V2 M
- \4 w* C3 |- x6 S5 m
//addr_len是一个传入-传出参数,传入的是调用者提供的缓冲区的clientAddr的长度,以避免缓冲区溢出。
8 v% B0 Q! I- ~7 A" V! V8 z, ?% N5 T; _- m: u
//传出的是客户端地址结构体的实际长度。
/ S" J' q9 v7 T
% \* P, H, T! H; z8 N. g" m8 ^//出错返回-1* P2 ?7 @( v8 N0 i ~( Q
7 |- U F: m' D2 X; H
client = accept(serverSocket, (struct sockaddr*)&clientAddr, (socklen_t*)&addr_len);
7 n: m% _( C- G4 S, z: M
: m/ F5 A) j; l' \( xif(client < 0)% Q' _9 d5 p4 z- n" R& A
' k5 P, Y+ `3 `" Y, l% ]5 ^
{
7 i6 W, o+ w0 `! N
- Z6 \" G5 d- E1 @" D+ cperror("accept");5 _* H! J- m" r! N9 s7 \
" |3 o0 c8 {$ d( Z# S2 u
continue;
: G- d6 S t y9 F1 ^$ F& M
' Y; I# W, r1 k}( Y0 l' Z4 L% g. ~, H2 o
! p5 E% B d' v4 @# y
printf("等待消息...\n");0 f j% f4 V/ z% z& i6 K2 M3 [( _
0 K& v/ T* S- X9 l# l) E1 s
//inet_ntoa ip地址转换函数,将网络字节序IP转换为点分十进制IP- s6 D& U) `- h+ \5 L: O
5 R* e) I1 p" y+ W0 C: U9 z7 f
//表达式:char *inet_ntoa (struct in_addr);4 r7 e/ Y" L0 R4 n
- p/ r* m( q3 o8 e' |/ G: \printf("IP is %s\n", inet_ntoa(clientAddr.sin_addr));1 D7 X- A7 |. z. W
9 m9 S R1 l, o M* e6 v5 {printf("Port is %d\n", htons(clientAddr.sin_port));
- \& U' M W" A
" R3 y- D) K2 i: c' m. }while(1)
5 Y& o* N& i2 I* O
! z! V; V" X, _) G5 {7 H" y, y1 c' D' ?{; ~5 W$ N5 q& U9 C- c5 j
- E' ?" z4 n* D' P& [) p
printf("读取消息:");' `8 L0 w1 {! `
0 \1 s; z' n5 n# p4 W6 Abuffer[0] = '\0';
0 T" ?$ J/ `9 N" k4 D8 y% Y/ }& i
; o5 H. ~2 ~: I% uiDataNum = recv(client, buffer, 1024, 0);
) Q* U) C. \- p' h& e8 m+ ]" e1 B1 P5 F5 R1 g
if(iDataNum < 0)
. r3 }9 @, X9 z% B3 K; h- i8 b) y( t6 C
: b9 l6 _5 @. Y$ V0 [- O{
& X/ T" `! C7 e: ?# x' A5 X* y! z% K+ m! t# t* L% `2 ^5 s% r
perror("recv null");
/ c. ~( t/ i# F! Z* _1 c
4 W0 ?* @3 s2 x& p8 Y9 Gcontinue;: @ K+ b- w' Q: c4 s
- j, w" b* B! R) W/ P}
& |- s. v3 L) f& n, Q6 ~1 h/ ?5 a
buffer[iDataNum] = '\0';
( _/ |( G/ b5 [
5 q! U7 s, M& m+ Q0 ?" ]if(strcmp(buffer, "quit") == 0)$ A8 d0 R5 D6 Q6 M
* k" e( K7 D" h
break;
% O4 r. O4 f8 s- |9 Y+ Y( c8 ?7 Y# O5 b; z. D
printf("%s\n", buffer);- [) a) V7 q' h4 O! v2 [ P: I3 c
; d" q- p3 |% H q( g3 x! `: J3 I
- D1 K7 {% u/ V5 }; D% N/ u
) {( b! g' u8 Z# J+ f1 Fprintf("发送消息:");/ ^* Y T1 V# W) u/ d
7 `( e7 e, D$ a& k2 W
scanf("%s", buffer);
$ T& A: I( U0 X: o [6 `
5 N3 L$ e; K! O5 p6 p/ a- M9 ~6 Jprintf("\n");: z, t/ {+ m2 j0 L! }# P0 j/ y# Z; m
9 ? h- Y0 ^. X0 u. Jsend(client, buffer, strlen(buffer), 0);: ^1 o6 r+ m# S G# i
% o4 a$ M- y2 e! B& [0 wif(strcmp(buffer, "quit") == 0)
7 F7 k" I& l' m d1 w, s3 }; _6 N5 R, A, n
break;" O# f6 f* C( z; U+ Q" i
$ R" h0 K/ j: V$ q}
) p* W& }# c; Q" b4 C6 R; s& z/ P2 H( M, }7 K* Z6 n2 D+ i; |
}
2 x" v. @2 ?5 m/ J- C9 J# o( O8 U( v, j2 _
close(serverSocket);3 }+ b7 U7 T/ b/ F( R) }
$ v: ^; ^0 d A4 Q/ ~& Mreturn 0;
0 E& l' k/ H# A4 n' D# Q8 k
+ |' a* l* O9 Z' y2 H}$ o- f, @# D9 H( e; _( _
client.c
2 O. H; t9 x$ a9 K#include <sys/stat.h>
" q! w. o( j) H5 y/ o7 d2 l1 q) x) V* d1 g
#include <fcntl.h>
2 D2 a: r* j! e
2 O1 g t0 c( Q- k+ ~#include <errno.h>
, v% F6 d. g2 x* ]9 i$ V9 t' d$ T$ \# M
#include <netdb.h>
' |9 O2 N! Z1 }! d4 E' w- t+ x( L% ~+ T; r& w
#include <sys/types.h>
7 n7 R. ^5 b' c [, `
0 j, `4 S. S) d% n( l0 G2 q#include <sys/socket.h>& i$ S4 \3 ]3 w l( ^5 a m
2 f5 P, a0 h& B7 j; C( [
#include <netinet/in.h>
; M' n! h) j" R; Y6 v7 m q s# e( x4 a: _! S
#include <arpa/inet.h>
$ R& K) @$ r& M0 d8 |" d H# ~3 b& ?8 t1 Z* O
#include <stdio.h>
# n2 ?+ [) y3 D; _+ e% I. I1 ^5 \ }1 i6 c, k) {. `8 @
#include <string.h>
k( \; J( L- i0 T: p4 x! w7 G4 c3 Q- p( u6 x2 \
#include <stdlib.h>0 j8 L v7 n5 u% S3 T3 x2 y, t* p- h
! U( }$ p8 a4 }6 _; Y
#include <unistd.h>
* d# I/ o& H0 Y, p# O# D) B6 F, ?
#define SERVER_PORT 6666
/ t9 e& j7 N! t6 W) o2 D$ I" S2 K5 P& k4 O, c! j
/* [- }/ N! I$ z. I% j7 V
连接到服务器后,会不停循环,等待输入,
8 r2 M% R9 s, i; [' y. o/ e9 o输入quit后,断开与服务器的连接7 o4 J1 Y" r# N1 o! @# z9 L6 Z) @
*/4 w0 J. R: P8 F0 y2 j0 r( o* l
. Y* `- P6 S0 Q" j S# yint main()
! ]0 h/ h7 T7 r' @8 z3 t7 u6 I
5 x4 O- a" l/ @/ e3 B{
3 Y; [& C0 Q8 ?( W d6 O6 K- O( u; A* Y* l0 B7 t2 V1 W( F( j
//客户端只需要一个套接字文件描述符,用于和服务器通信
% q; n" H) }4 \( h
, x8 R7 o9 V5 M# n& |2 nint clientSocket;
/ E. |0 q4 \; m3 r. Q1 Y2 w- _& n; A
: b- t, r% D5 }( x, i, F! l, n4 u//描述服务器的socket4 q; b! x- D7 k' J% ~# B
, ^5 A8 E0 ~6 A# T }# qstruct sockaddr_in serverAddr;# j5 R0 F( {; I: J% s+ [
5 f' X- J1 t; c$ bchar sendbuf[200];
* Z1 Z* x$ _2 A% n
h8 m, Q8 h1 v, gchar recvbuf[200];
8 L3 h5 R3 O% B6 d
; i4 e1 e9 z* T% Z" Cint iDataNum;4 V& I; p3 i, _0 G9 @3 i
% n: y. Q Y& r3 h, V; m7 |6 I
if((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)4 S: X) W- [- ^
0 k0 D% H! U4 y! \$ Q{
6 |5 Z' e1 ^+ X& h& |& \$ ^6 R0 ^. z' G- R9 v
perror("socket");7 f+ d0 P% c2 `! `
) {+ K2 c- B7 n+ u7 G p$ e; Treturn 1;1 L/ Z' @/ _8 [3 m0 Z9 F. b
# H9 j4 v* E+ ?% A}
" y9 @ a7 Z- f9 F3 c% I
( t( F* E1 q7 Z* [serverAddr.sin_family = AF_INET;# Y) b, C) d* G& K
' k& U2 B; O1 I3 e' r' D" F5 BserverAddr.sin_port = htons(SERVER_PORT);; W" K U+ E# M2 h6 r- X+ o
# u4 n. b0 P& v8 v
//指定服务器端的ip,本地测试:127.0.0.1' j& C1 T5 A( L. \ i6 A+ z8 w. U
$ a* G7 ]0 `( c! |4 n7 R1 i
//inet_addr()函数,将点分十进制IP转换成网络字节序IP
T) n8 a' ~) V: f: {! t/ J. }. A$ P
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");! T5 m* ]& q) j1 b6 @
, |4 Q) W* i5 ^if(connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
' [, X9 ~8 y+ j* V
& g& X2 K: d' Z6 \9 s8 L% _7 \; _{
0 h$ U0 F+ o( ?+ d( C8 H
0 o- e* C0 k, G7 c8 I0 k2 v" Operror("connect");
) i0 Q/ d# f2 g( Z7 V
$ i9 T. s) G1 A% U' ~return 1;* V3 ?% p4 `4 B9 s/ X1 _" \6 j
) `! I+ j: |1 _}
; D' W9 j5 y) b7 G3 @+ O" f6 k
, f1 `. Y# d+ b7 g8 K3 tprintf("连接到主机...\n");" Z$ m) X2 n: p2 S1 a
* Y$ k$ t% I- {# l
while(1)
y3 Z! H0 E1 U( c. [: f/ [. Q* o0 h$ Y" [7 R( g: \% k' v/ U
{
& n B- [7 O) J% Q2 U2 b9 W. W' {1 |6 x; v4 h- v9 B, s! W& r
printf("发送消息:");& C8 }6 ~8 [3 G% z. P9 K; B
% O A8 e/ X* b, V- t4 ^. C {0 q- J
scanf("%s", sendbuf);
9 r* [3 g" y1 o6 P, Q
/ H4 _* ]! p5 K3 o8 l& G2 U1 Aprintf("\n");
3 o, t) r% Q5 R& m" O9 l+ e
! {# q \. g6 e. i* _2 jsend(clientSocket, sendbuf, strlen(sendbuf), 0);
8 n3 g7 N5 d8 q
1 O# [0 U" H. ?) `: H
! f, t9 t4 e! i- ~+ n; L/ T( L5 E6 m" ?5 x
if(strcmp(sendbuf, "quit") == 0)7 T. B* E$ j+ d7 U! _# l
) q* Z6 F1 O2 i* | Z1 gbreak;% z* S2 ]1 g/ W' k. A0 D1 a
, U, J' Q2 E0 X: M# n2 k* x: l. P2 [printf("读取消息:");$ o) j2 O1 j2 m2 E! W) \6 W4 T* J% f4 o! `
9 F i0 D1 }: \9 @7 s+ ?
recvbuf[0] = '\0';& K5 g2 W3 ]- ^+ e7 `
3 Z* _- Z" I. { xiDataNum = recv(clientSocket, recvbuf, 200, 0);; \/ F( |4 r( x" {* M" w& o
C! E& r! e6 erecvbuf[iDataNum] = '\0';
$ C7 G: u- X- e) b+ f: o+ v1 m& ]1 _! K' j- v6 ?6 D
printf("%s\n", recvbuf);. v9 @% A, u6 j) l: s! R
+ [7 h0 q( g8 x) p6 e
}, R0 h1 H d7 y" N5 h( `
: o: i3 x/ x. e X( N. Lclose(clientSocket);/ `; _! _8 Q) |/ R8 }( p @
6 r* W3 ^" i, X
return 0;$ G3 k4 e# F8 R- m
+ s' x9 `% F% W1 t" o' D6 e
}# a+ Z6 w) ^' f( q" K
4 }- C* h+ e4 C |
|