|
|
C语言实现TCP-IP协议服务器与客户端互相发送数据的socket编程
) x* o& j+ ]: e
# A' X8 B8 s% N6 Dlinux下用C语言实现TCP/IP服务器与客户端互相发送数据的socket编程
v( k( i! U4 k7 S+ P6 j C) }' l% N
server.c2 Q) V- F; m6 c# {
#include <sys/stat.h>* ^1 q- C5 S4 o8 z5 N
: n0 t0 ]+ Q- X, R#include <fcntl.h>0 r6 j) n- l- Z$ F" P4 o- o
+ t3 z( o& {2 r" T2 P6 k7 [4 D#include <errno.h>
0 H: t* h4 I3 O# C3 C! ]3 n5 e$ i- O+ R; d
#include <netdb.h>' g" {" f* Q9 I s% F. n
' j m* i K. T: B& L
#include <sys/types.h>( F' m: |- J5 n8 p" J
& l! B C$ h6 E( O! r
#include <sys/socket.h>
$ B5 P. a) w Q1 p; W4 j8 x, y, [4 R# @
#include <netinet/in.h>7 A/ G. X! l; u, M4 E) U
* p" c% N e; Z: U9 M1 O+ @2 g- I4 B
#include <arpa/inet.h>
7 X0 ]. t" g0 F& H) W( V
) r9 l! {' N. }7 m8 A, M#include <stdio.h>6 _: a$ x. }& c, Q- w5 Q
( F7 U' O: H( B) G3 e#include <string.h>. j2 n( u5 L/ b# [6 l, J
$ J0 r, R, S1 B6 k#include <stdlib.h>
/ m4 l7 |. F* M7 p/ L/ q4 K3 [$ D3 @7 Z" ~# O
#include <unistd.h>
5 }1 Q' ^/ A i+ A; s: |
9 R5 q( H3 A9 m#define SERVER_PORT 6666! Q D( Z& K9 K" ^& H L: A
5 ^1 j9 M) c; u% z! o. A- n
/*& o* u B* `6 N
监听后,一直处于accept阻塞状态,
# Y. t8 [8 Z& J3 m8 W直到有客户端连接,3 e0 E' w( f' g
当客户端如数quit后,断开与客户端的连接2 S3 b) \) W( B8 [8 y1 ]5 H; D- D
*/) l) v- y% Q0 Z8 D# d" e+ y
* s# C# x# v+ a/ A, s+ g6 K( l( |int main()
0 G2 N m7 S8 Y$ U3 D9 j& \/ I
- p& d9 c% m- E) K6 U{
$ z. z, J: A2 A' {' ~9 ~4 s- _; H$ O% e# n
//调用socket函数返回的文件描述符
" w# R& e8 S' s9 y8 d) F9 _0 ?- Z f" x8 e' d) V) ]
int serverSocket;; J5 }* M+ F0 O2 p' F
; g8 Z5 V0 {1 z5 \5 {
//声明两个套接字sockaddr_in结构体变量,分别表示客户端和服务器2 j* D9 ^- n$ R
( M: d! Z9 O: t# Lstruct sockaddr_in server_addr;
" i' }4 H; I$ _( M1 l, b) ]8 W( V C& ?6 y
struct sockaddr_in clientAddr;6 h* r' C3 a2 v. y' e+ ]
5 d, ^$ w( _- W% G8 N' e0 y) E+ q
int addr_len = sizeof(clientAddr);
9 e2 |- x# C7 y' \! f; x; `9 z* i4 q" e% g7 F
int client;0 H. }; S x' V$ y! D T
- k7 _: l0 q( e& `4 U# m6 b# N
char buffer[200];
8 m" `6 I9 r/ m0 Z9 G! }8 J: ~ ~' @) w4 F' s- L
int iDataNum;
5 i: H5 L; v, b, w( g# I' j
4 h% @) \; ^7 z7 i//socket函数,失败返回-1
5 q* M2 w7 l0 C7 ]+ n! k1 \# m# K6 S; j6 ^% `
//int socket(int domain, int type, int protocol);
' \8 [1 d' P) W" \- n% o \9 U% t& l, D: C/ n6 ^
//第一个参数表示使用的地址类型,一般都是ipv4,AF_INET! h& E7 ?4 g5 y5 c) I* L ^& B
G" I% @3 [+ I
//第二个参数表示套接字类型:tcp:面向连接的稳定数据传输SOCK_STREAM$ j" E9 K, S6 ^5 {+ z: S
1 s n& R/ X2 W3 m5 W* X//第三个参数设置为00 ^1 s9 W! E) w6 t) C
% `2 ^4 L% e1 y% eif((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
' j8 q3 M+ [7 r
9 E# y. e; w$ j$ {9 k{3 k0 d B4 ?3 o
{- q9 u) Q, w, k% Yperror("socket"); {6 y6 v7 `$ Z4 `0 T6 I' h( i9 b9 d
+ ?" A! j4 [2 L+ U
return 1;# \( q% \4 c8 V5 b
& h3 P# K1 m8 H* l. `$ O0 F Y}
( \+ `! o! p% H7 p p. O/ T: ]
, a5 j( |$ W x. Lbzero(&server_addr, sizeof(server_addr));$ Y' p6 ]3 N' |6 ?
( v2 U" z" q5 D; u' q7 a; T' L
//初始化服务器端的套接字,并用htons和htonl将端口和地址转成网络字节序 |) Z+ ^$ j( Q! ~/ ^
# @4 ^ b% ]9 x3 U9 r0 {server_addr.sin_family = AF_INET;/ E8 K: j$ g0 Q+ l) P& N* W* J
& u' z: B! x# R6 V& o
server_addr.sin_port = htons(SERVER_PORT);
# _" i0 ?: b/ D. f/ X
4 E9 h5 ^4 o+ y; M! j, |: J# q& V//ip可是是本服务器的ip,也可以用宏INADDR_ANY代替,代表0.0.0.0,表明所有地址# s' ~& Z& f$ p% l6 `
8 ]3 x# O; q/ P) X
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);6 r. s8 Z) g2 J& C# v% C
) h# o! _( L8 A: E3 t8 t
//对于bind,accept之类的函数,里面套接字参数都是需要强制转换成(struct sockaddr *)
& i5 `0 w* I1 K/ G8 r. J( l8 \% T, `0 K" R# s2 J
//bind三个参数:服务器端的套接字的文件描述符,
) O1 [( F" z X; v# B2 f% p
1 h" C' w" m5 \$ Z' x& k* J. lif(bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) ]# U6 c7 ]$ D' e" o. W4 T
! M, z: X# c* G# J1 C7 D& H. @{$ |$ r; L% v" M( g P0 s- y% f
9 F Q3 l ^ U" T5 k
perror("connect");
6 I5 l. e8 _$ ^6 Z
3 [- d6 w5 \! Vreturn 1;
5 Y. ^- \' j1 Z+ \
5 h2 X- ]# c7 l( @) b/ J+ m7 Q}
) i2 l2 ]) A3 s; U* X, h) Q1 | ]: o
3 i+ G4 F; I* X5 t* `6 W% I//设置服务器上的socket为监听状态' [' N( q @ N( v' q) y. ?" K
9 _0 N1 p7 F( ~6 O
if(listen(serverSocket, 5) < 0)0 o, c8 ]- x1 Q6 w. z
7 Q5 ~' ^, M# T6 L+ s, t$ {& F# B{
$ [% t) ^8 I2 {" A8 K3 E- t/ I' v+ X+ V
perror("listen");. N2 q8 k+ c0 a3 r
6 S: L/ y0 c* ereturn 1;# c3 @; n; _) U# w4 `: l7 H
8 L, w0 G" L) e9 T" ~& ?' p}, v8 a& a2 k5 W/ j
% j0 t1 Q0 w6 C$ F e. U: {
while(1)4 |" ?5 d) W$ E- g: H
# B$ A$ [. w3 J. t( H5 i{
# l! s6 i" ]/ W9 X9 x
& D& d8 D5 |, ^5 ^* \5 t) |printf("监听端口: %d\n", SERVER_PORT);
3 t* [5 t5 G3 G1 u* E; k, _' t/ v5 Z7 c
//调用accept函数后,会进入阻塞状态
& A7 W! p0 o& L9 `* P; {$ T
) n. o* j' t6 e//accept返回一个套接字的文件描述符,这样服务器端便有两个套接字的文件描述符,
" B& V+ L" I& f) Z! ]
% u. q1 ~# Z! [# N- F; ?& Q: P//serverSocket和client。* @7 h0 ?# i7 D k" R( y2 k
* z p7 i( ^) j9 n2 {//serverSocket仍然继续在监听状态,client则负责接收和发送数据# y& O' ~! f5 z) `+ I
! b8 Q; q. G" R: ~5 W, T/ Z& c
//clientAddr是一个传出参数,accept返回时,传出客户端的地址和端口号
4 X: G* s' \% l7 O8 z: ^2 m4 b& o+ B' _9 u; m
//addr_len是一个传入-传出参数,传入的是调用者提供的缓冲区的clientAddr的长度,以避免缓冲区溢出。
6 ?0 x5 W1 ~* ~9 N5 ~* s0 g2 Y5 A+ K' m& i
//传出的是客户端地址结构体的实际长度。; o! e! F6 Y8 x) Z& e; p
- N3 u2 ?4 y' z' T/ Z
//出错返回-1
( V9 S/ V" L: \" w& g* D _& r+ y; |& C8 B8 B! O9 n
client = accept(serverSocket, (struct sockaddr*)&clientAddr, (socklen_t*)&addr_len);
9 H0 v$ {4 Z" N* O1 v: f! {2 K- W+ J9 R! V
if(client < 0)
/ N' a- Z& I- [; c
( f3 h! @. A8 w% K8 x: T- B( g7 H. I{
+ U+ K! a& U8 `: i8 x0 G
, ^/ M, w( G+ I7 dperror("accept");' A! ^. u4 S; r5 F; A" @
" {( }: o4 E4 S* S% `+ Kcontinue;
! R1 J, S( S: v; A/ v$ k$ L+ k. f( q
}
& E( A# K- k$ ^3 y, B
; f. @) K# U1 m% @printf("等待消息...\n");
0 ^' _' O0 r. s8 B4 ]+ Z
4 S6 x, L7 T# e( k//inet_ntoa ip地址转换函数,将网络字节序IP转换为点分十进制IP* G n2 J$ M1 T' y" j# f2 F6 r5 c
3 m, j ]( P5 B//表达式:char *inet_ntoa (struct in_addr);
+ R- s- v/ q/ c2 G% y3 R
- c# C R; ~. x3 i" O' Iprintf("IP is %s\n", inet_ntoa(clientAddr.sin_addr));
* `% R- S& h( M7 w% [7 B# d8 B: n0 S
printf("Port is %d\n", htons(clientAddr.sin_port));
- f0 _' t, z" O9 B2 u5 b' j2 D F) \2 t) N
while(1)* q8 R, U' y( G
9 }" U8 f) \8 v0 W{9 X, Y. q* K4 z% K
% x3 \4 E9 t- `$ tprintf("读取消息:");4 C# q7 G3 D4 [5 v L6 i( ^
5 }. q0 v. T) |& X* P' L) z
buffer[0] = '\0';1 t7 w# J# f4 S9 D/ ]
. N2 t W" t" b
iDataNum = recv(client, buffer, 1024, 0);/ V8 U6 C1 y% l5 |8 l
9 {# D/ [8 J' p5 eif(iDataNum < 0)) f: e1 I, j0 ~' d8 c' H: A+ l, H
; F& l, U; B6 p2 [# X, k9 S- t{6 L. I; V2 q; a# y2 W4 [9 M
6 K. k7 t( w* l7 `1 J cperror("recv null");+ C& C0 r- F! J: m G* o, U+ ]4 r
# q9 J) [$ s% v
continue;/ G7 h4 ^" }, Z! p0 |
. w) |' W2 D; F1 @/ d/ Y
}
1 a: e5 J/ ]" z# H+ L: _4 W, B) E
* V0 J/ Q; Q- _2 i$ Obuffer[iDataNum] = '\0';$ s8 A6 ]+ c H" y. h. K
' T" L# d# [" ~3 V: @
if(strcmp(buffer, "quit") == 0)
6 r% {: x! X0 ~ E1 O. R- o# b' h( y' ^, N% E
break;
( d1 k2 E' y7 f" l/ b1 p1 {" `# `
. `, g$ _& n1 j/ R# Wprintf("%s\n", buffer);/ |3 v! z9 `- _& B+ @! l! H" V
7 I/ z* V$ W, Y6 {* D/ N
$ S) }& s3 O' u* j
$ ^" A: u" P8 @6 K% G
printf("发送消息:");
. `0 R( B% |9 l; ]. L) ]! F. ?7 k6 M9 `/ Z8 f- t# @' c* v; ?9 h
scanf("%s", buffer);
9 @) y* c6 ?/ P9 {& N+ w8 _- C) x# O9 W2 d
printf("\n");
/ F- p p- Q2 F7 X% C4 A2 I# y
8 ], V: J6 `0 x/ }+ O0 O z6 T+ Usend(client, buffer, strlen(buffer), 0);
# B: K; ^0 H- z4 f) s7 U; d
! J6 i, E' L7 ]1 i& eif(strcmp(buffer, "quit") == 0), U3 ]6 U) q6 E
) c6 z& N1 h# C' {( t+ C( Q
break;# ~& A7 X$ G, S% P# q* }
2 `: {: I4 l1 N4 f+ A4 r! B) a
}0 ?* i" ~6 i @( A: d( d: ~
4 u/ N2 w6 B5 s0 `6 R8 M2 ?! H4 X; Y}' i9 f; d4 x6 b7 p# V4 G; \
4 H8 e8 r2 P `. `% X: Kclose(serverSocket);9 p7 y- E' F3 A
0 V0 \; L+ [6 n2 e% x+ ?
return 0;& f& A* I, @' l& `' _( K0 s# ^( I
+ u3 I: x1 y; O8 ~' ?, C9 z: g
}
7 _# X. o8 {* m4 P$ X; W7 R9 pclient.c
% K6 x. e0 l% t3 l4 ^0 p; Z* C* V#include <sys/stat.h>2 z# g+ j+ E8 D) I6 X7 e& x
8 ?8 L) v, ~7 `( x( g9 O
#include <fcntl.h>& k/ R- z8 h# U# i8 r
6 {6 u1 R6 \# ]2 _% [#include <errno.h>7 x* g) b% W$ _% G7 L
! }2 ~* X t) }
#include <netdb.h>
- P& U2 t ~' _. B6 q
/ M( X+ \2 {0 H8 V" ?7 ~/ U& w& N#include <sys/types.h>5 l8 L) d+ z5 T. D# J; [( X7 O
2 c2 a6 C; E6 C6 A+ X
#include <sys/socket.h>
5 B! t' {4 s7 ?4 K
+ U7 ]3 E$ f1 g: W/ y#include <netinet/in.h>
( S+ v: H3 v) }$ u: }+ m
8 P& }% Z: l8 V( l# T#include <arpa/inet.h>: [, j/ G/ x7 c' U6 m! z& `$ d
, j) D! q Y6 |' T5 _
#include <stdio.h>
, J) x% v8 e1 s3 P, _' j0 @
* z r$ L! g' s0 f0 `0 X- S& \7 d' {#include <string.h>
2 M1 x# N& ^7 C+ P# [6 R, B- S1 Q* z% N ?
#include <stdlib.h>
" ?; N# _& ?1 p$ g+ h* C3 q/ V- h( H5 m2 i
#include <unistd.h>
- w! x: |# e. M6 f G7 d) U" W: ?( a3 {. p% \
#define SERVER_PORT 6666' z* z- p' y, s4 J4 A" e* ?( L* D
5 I- F- z. a3 f. h+ Z/ x! i/*
% c/ Z' p0 _; q& P8 E连接到服务器后,会不停循环,等待输入,' H5 h0 P, v8 }0 L. {* d( x# _
输入quit后,断开与服务器的连接: ^' D6 j+ u* `' t6 w
*/- S" g6 \! T$ G" g( x9 j
. Q% @" p5 s5 l; ?9 U) w
int main()/ I' i7 X) O9 l, v
& T6 N8 P9 a' {5 s$ u! Q
{/ v* ]; X9 U( \. T2 j. z& ~/ t
) [7 p1 e2 S' n
//客户端只需要一个套接字文件描述符,用于和服务器通信1 A+ _1 ? K b3 E1 p+ ? q- n
3 ]4 z* b; D* ], fint clientSocket;
! x/ u8 {# M2 ?$ z3 f0 C3 J) I; q
//描述服务器的socket
, K4 D4 D6 Z) ?0 n9 C
! q( X( f: ]3 p) Rstruct sockaddr_in serverAddr;. P" e& g T: J* j
: Y8 T3 `1 D% a" @
char sendbuf[200];
! e$ g/ S& Y) o9 I v! o$ ]
% X2 x8 p G4 M8 x- wchar recvbuf[200];5 O$ C4 h. j! j& y
# z4 a7 ^3 z* K$ S/ g2 r+ yint iDataNum;3 }1 A. M5 A* T, h, B
1 ^5 e; i3 z# M% M
if((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)5 m4 ~! }3 h# \
, W6 d- H, I) S{4 s0 c% [" r/ J, V
. x, L% P" P& y+ \8 {5 H
perror("socket");0 g4 F' l0 l: w+ Q! H/ |
. k) b; g/ z: C' u0 P: J9 ?) Vreturn 1;% q, v* ~' ?6 o1 ~2 l
, K) h" W! o/ A/ @( O. B; ^6 D}2 c9 p% L: y6 n3 {6 d
4 P% t3 m' r. u4 Z
serverAddr.sin_family = AF_INET;
4 P% B4 i8 I' o3 o7 Q1 S
R* y" ~" f$ @serverAddr.sin_port = htons(SERVER_PORT);9 n5 q0 _. {; D4 n- ?! r- m
+ ~, {$ L- C: S//指定服务器端的ip,本地测试:127.0.0.1/ {0 N- I* a' n: }- ]
1 T# B0 B) v$ ~" E+ X//inet_addr()函数,将点分十进制IP转换成网络字节序IP/ J# |, V- `8 s1 Y# V I1 n
: y) t$ x( A' t3 U7 R# p; pserverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");0 M5 D6 U" i# U2 h/ S R3 _6 i; o I
) w4 y8 D0 D, q: Z8 `0 F& C% w6 kif(connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
/ q! N7 h; _! S* [/ R! z5 b* }$ m* o. m4 g+ p/ d6 ^" N4 n( Z2 k
{
1 S4 W7 K3 W" Z N6 Y% I. L- T& o
1 f, g% }& D7 uperror("connect"); P/ K( N# d* A3 n- n; U/ S0 x
3 }1 b- K+ R. y) nreturn 1;
2 X1 z" h; g* ~: l$ m6 g1 C5 y: a4 b
}( w+ y5 W# E+ u) T% t* z( y
5 M% F2 |) @$ E) s' S
printf("连接到主机...\n");; Z; v0 b, o2 K. M
6 T/ @; F7 k" t j* g( ^while(1)
4 O0 V; r8 H2 T$ X8 o$ Q
- ~/ Z$ }$ f' c, h% Q7 e{; Z2 O$ Y0 T: x( U0 L$ \9 C
) h2 `) c6 W% t9 z) C! }
printf("发送消息:");
2 K/ ?$ d9 f1 d) ~: p
% i; [5 A+ v. A; J) |8 Bscanf("%s", sendbuf);
0 n3 c: U. M* Z3 n7 v2 [3 C: p8 I$ X$ N9 m
printf("\n");
( J: ~1 W5 b9 L4 I5 @, D
6 W ~' P9 M' r1 ^send(clientSocket, sendbuf, strlen(sendbuf), 0);. |! {- A$ C2 J9 J
" M5 m. y7 M6 j0 A; l0 ]
9 l/ R" A4 w7 J6 L, ~
/ t H9 m8 U. u- {3 cif(strcmp(sendbuf, "quit") == 0)
" V0 ]4 M& G/ c9 y, j
2 E0 Q) S% E4 c9 y/ }, \- H" x, obreak;# A( F1 y* D( \
. `3 X! v: g1 }& i7 P3 \: Sprintf("读取消息:");
9 r v. l, f' y. ] G, v
+ M) |9 U0 S$ ]4 Irecvbuf[0] = '\0';
+ s: H1 A2 M/ N7 g& Z; h; Y- E. j9 g& L# ?' k# X9 I1 `' @
iDataNum = recv(clientSocket, recvbuf, 200, 0);
! {- u' F0 N6 Z: M
1 _& T3 v% z5 v) a e' |8 J7 erecvbuf[iDataNum] = '\0';
: ^; V" a; T6 f7 j8 v/ U
: ^8 y. p2 B% Vprintf("%s\n", recvbuf);. |' V/ J! B5 Q: {& u
+ u, ~4 m( G! d6 g
} m' u \; a2 z- a( N/ Q
0 W( {2 \* e, h
close(clientSocket);
4 h) u, G5 [1 Y" c: U3 C1 Q- V0 L7 b4 D1 J p* y
return 0;! Z( k# R/ Y* ?+ [
$ {8 j1 T8 O6 Y
}
" t. t! H0 m5 M8 H) [4 k5 Z6 T+ ]8 x3 F5 u/ m5 c; I; V$ E- y4 M
|
|