- 积分
- 16843
在线时间 小时
最后登录1970-1-1
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?开始注册
x
C语言实现TCP-IP协议服务器与客户端互相发送数据的socket编程
9 e, o9 N3 _4 j' {, i
7 @" |/ {# W* j0 Q+ y( Tlinux下用C语言实现TCP/IP服务器与客户端互相发送数据的socket编程
) C! I! `; I5 ?- h! H+ X; e% d* X4 _8 ]( I
server.c# R* R8 l% x: K
#include <sys/stat.h>/ l' W4 _1 h& I' k) d
, V0 n* U2 p$ T" f3 i
#include <fcntl.h>
0 ]8 V! i/ b( {3 O$ g/ d, ]' ^3 `. T! l' b
#include <errno.h>
( a2 D4 T+ r) K4 O. a7 l
( R. b( p9 ^) I( \#include <netdb.h>
/ P% N+ Z! ?: m3 B
1 S1 f' m3 y- x0 W0 t. @( T#include <sys/types.h>5 w, {, C4 f: E: i1 X5 x
0 N: a+ D. @0 g: u#include <sys/socket.h>
$ P( w6 V x+ l* t$ r, o, `$ q7 K' a* E& {. X F4 S
#include <netinet/in.h>1 \$ w: G2 u% e
$ e* `8 m9 g2 _' K/ c9 a#include <arpa/inet.h>$ K' V/ }5 x5 ~+ d1 k" g5 c
# ]( `6 Z# _4 b9 @6 M- D
#include <stdio.h>
1 [9 r1 p! e$ b
: t% s- e. o1 y/ w& w: L#include <string.h>
J1 S6 T& m5 @( K1 {6 t- }0 k$ l, l1 }! Y6 w
#include <stdlib.h>
/ d+ ]4 I; u, }/ H& j' X- R* I) |; F6 y
#include <unistd.h>4 t# B6 b/ h/ m$ _2 o
! f9 M E4 ^( ^#define SERVER_PORT 66660 j0 s3 l$ z' J; r
+ n) O/ p5 b4 d2 ~
/*# i# R$ h8 A, {8 q2 y0 M4 p
监听后,一直处于accept阻塞状态,
% T8 r L, y9 ^+ J6 S+ c直到有客户端连接,
6 L% V, d6 y! d% y当客户端如数quit后,断开与客户端的连接
+ r8 y$ {" l( P0 m6 r*/
& m$ G/ ~) K% a
* n X+ V6 i S5 }* s* M- }" Bint main()
: n$ p8 X( \: ~, S
$ Z( ]2 h" G/ G. Z" q) x{4 x+ S+ G+ S% H( `) J4 X
# h& Q, @8 |" q, `* _3 B2 |5 J//调用socket函数返回的文件描述符
6 K7 a' R- q3 ?& |4 Q# E* `
* `1 C! I" P% k' u+ C6 `/ G' bint serverSocket;
, k, F) y0 x2 V8 x C; ^* f; w& h: ~! B4 p" C& ]* n
//声明两个套接字sockaddr_in结构体变量,分别表示客户端和服务器
1 @. C: i. U1 `+ d3 Y6 A; M+ g6 `: ^' A
struct sockaddr_in server_addr;
+ n& d! U; I+ X6 E5 d# k6 Q
* s$ k- ~# ^* j6 v4 @) {struct sockaddr_in clientAddr;7 o6 V7 [) o. l; E
& `2 z) c5 p. e
int addr_len = sizeof(clientAddr);
$ Z& z$ [6 x& d. f/ l1 ]3 W
- w) ?* X1 u/ F! D! B+ tint client;+ s* Y4 V6 e8 ?. s; r
0 }1 H7 [* \% [' ^3 R5 _char buffer[200];9 C& T! k4 `! o- _/ H: t
+ ?& ?. |6 i0 n7 iint iDataNum;! s- `, y; j1 @6 y$ S+ S
5 [) G5 ?- q2 C
//socket函数,失败返回-12 F! W+ a/ P) g( s- C- I( m3 A
+ i! y! O0 U: I/ X6 G
//int socket(int domain, int type, int protocol);
# c8 A; Y! b2 ]' i- N2 p& M$ z
//第一个参数表示使用的地址类型,一般都是ipv4,AF_INET
5 G* i8 c3 D% j+ j+ l9 t% J+ b. N, V: N8 p+ \
//第二个参数表示套接字类型:tcp:面向连接的稳定数据传输SOCK_STREAM2 E: X) L, Q. I1 E) h
3 ^& t6 Y9 X: d1 X//第三个参数设置为05 m$ j. S& v$ M1 b; `
& c' B- y% ]: j* K; y, V
if((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)/ j) F+ C6 k/ ~# N5 e
+ J m8 ?9 a# O2 N# t{
5 N( a1 }: z- o% j7 J/ v: i; b5 u+ l1 ?, N# \9 i( R0 x/ P
perror("socket");
7 k7 M2 j4 z6 k* r- ~( l/ B
( @* C1 l2 N# \0 Nreturn 1;
+ G* f. ?3 H. j4 W
4 J& t( B1 i9 ^: z& z6 z}
( S! w( Q7 M/ e% Y: \4 a7 I: z! c$ s9 A# ~" w) P' V! g- b
bzero(&server_addr, sizeof(server_addr));: F" k7 z# Y5 b @5 N
c; a: f, Q. a2 `5 a
//初始化服务器端的套接字,并用htons和htonl将端口和地址转成网络字节序+ _ D S6 d, ?! d2 Z: D' |1 x4 B
; J- T8 N4 b& A( V ~1 U
server_addr.sin_family = AF_INET;
2 L; _9 C. u9 d5 _
% B3 p$ I) y7 e2 o- p5 W0 l8 Rserver_addr.sin_port = htons(SERVER_PORT);! m3 b* s8 d6 K8 Q
: J* m9 |3 D D//ip可是是本服务器的ip,也可以用宏INADDR_ANY代替,代表0.0.0.0,表明所有地址
9 R: `! G0 v! n6 Q! s6 L- C( k5 u" ~0 [9 Z' }, v4 B
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);. g M0 i+ E$ [% ~5 l2 q8 s
- B9 ?9 \ ^) t4 k* G5 ^1 Q+ k
//对于bind,accept之类的函数,里面套接字参数都是需要强制转换成(struct sockaddr *)( K( ?+ t& {' F0 `/ F! K, A" |
- a; F- f1 `: g3 j3 A//bind三个参数:服务器端的套接字的文件描述符,# F* N& [: _$ h: j( G( Y! A
4 Q" u# o" }1 F) N' A8 L" uif(bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0): e& j/ h: e {) z2 ~
4 x- K, x6 w( b& s3 A{6 \+ z, h5 \2 W. n8 E( K8 {4 [
7 p8 U* A/ y2 C" ^! m" e7 iperror("connect");! Q8 I( ?+ d; g3 E8 @$ i& L
0 V0 h' d% g3 B* {7 _" g5 m; y
return 1;" p! [! ^( Q* C. l9 ?5 R2 t
# j: b: D, x$ C9 ^9 D7 e
}
5 w; ~1 n7 X4 E3 z' b' h1 V1 [1 W' B( b$ m/ c0 w" A5 Q! g) I
//设置服务器上的socket为监听状态8 M' p' j' s% B% T) f3 T
" c9 L" \, @1 {5 Iif(listen(serverSocket, 5) < 0)
5 D k! q1 m5 z6 A! } R1 z/ a! i0 c! K" u
{
, q) M+ t) A3 o; ], v+ m
. K, Q/ B9 `5 l6 [7 @+ ^4 v1 X0 gperror("listen");
5 Q5 D. b. E4 [4 s2 g
) P' S; L; ]3 N# creturn 1;
B7 `# z2 _7 @0 T, d8 v7 \% N6 [2 h g# _
}
! u6 a3 I8 c: K6 F& P* ~
' K( ^8 g' q( D4 v; iwhile(1)
( T; P/ i3 B. L% p! W4 u O% A/ u6 z7 O
{; n* H8 K4 [5 N# x }& y7 D+ Y
( x1 Z2 Y0 Y' p% Z
printf("监听端口: %d\n", SERVER_PORT);
2 D$ N/ H8 S1 d1 r k5 X, F' r* y* j% ]
//调用accept函数后,会进入阻塞状态
8 ^- J7 l5 _) z
) F( K8 v# A) u+ s |//accept返回一个套接字的文件描述符,这样服务器端便有两个套接字的文件描述符,
+ f7 k0 T! V8 |' x. @/ P1 I
# z4 T1 e2 ~) q. X//serverSocket和client。
/ G# P+ X1 z/ t2 G) A' R7 v, U1 l- L/ [' G! E9 V
//serverSocket仍然继续在监听状态,client则负责接收和发送数据. J+ O3 v9 n( s1 w& k# I
2 s% l8 D9 r: Q, \: P//clientAddr是一个传出参数,accept返回时,传出客户端的地址和端口号
+ m2 T7 P9 \2 i3 A& _/ q2 `4 N9 n
//addr_len是一个传入-传出参数,传入的是调用者提供的缓冲区的clientAddr的长度,以避免缓冲区溢出。
# F1 r; q/ n% J* [& a& D/ W6 Q! ^+ {! a! D1 L( ^3 }
//传出的是客户端地址结构体的实际长度。
4 ~5 ~5 {, H; H, y0 x/ x2 F8 c4 r9 K [" K7 ^+ V7 a
//出错返回-1
8 R/ f% Q* A! p# h4 @" `" N- X
9 W. M1 v- R4 J3 o: hclient = accept(serverSocket, (struct sockaddr*)&clientAddr, (socklen_t*)&addr_len);
4 B8 e0 h, I+ p# A" _
4 Q' u2 \/ \1 R4 A" i( X \) yif(client < 0); @" W- y# B3 y
2 Y$ w* k. y5 ~8 [8 c+ |% M
{. k: Z' ]4 T" F% m0 h- y
" y! f; H! `+ _6 b: a; e: w$ Nperror("accept");
; K2 f/ D+ r" ?% K, q( Y, V" T8 Y' Z7 b" n$ |+ p6 L7 z9 O! Y$ x
continue;
1 o. y/ y( t% l* N
" N D2 ^* Z! O( c* P6 U, x}, B4 M# f2 G( K2 Z
; U- h/ R6 b" V6 r7 u
printf("等待消息...\n");; A5 ?6 x& Q( n' M$ w8 u. A
+ Q5 M' y, d: b5 v ? ` B# ~//inet_ntoa ip地址转换函数,将网络字节序IP转换为点分十进制IP
8 A, Q8 A- i: E1 f* y: g. i* n0 S6 D+ y' J; [/ e/ q- E
//表达式:char *inet_ntoa (struct in_addr); y$ ]# G8 x4 s3 C
% v0 e- W- p5 q% v, u. P8 Tprintf("IP is %s\n", inet_ntoa(clientAddr.sin_addr));" u6 V; ^: ~; f/ ^0 n6 o) y
% _4 V, \5 n+ X& y; B$ r; Q4 S3 T
printf("Port is %d\n", htons(clientAddr.sin_port));
1 c: [( U4 f/ ~& q( C2 v( r7 B
: `; |" F8 [ h1 }# mwhile(1)" y5 T/ w% V) c3 ?0 V! P1 u7 s* z
9 K/ S/ C, F; R& A4 L9 M+ f
{- V5 ]& c4 N# l7 r% D- L* ], w
+ F1 {" C8 H( C( Q$ ]printf("读取消息:");
7 G& Q8 I4 z9 i. m: q% f& n3 Z0 }( ~$ v3 E P$ v2 A* h% E! |
buffer[0] = '\0';$ A# O4 j0 d, P, B( j! [
" y: D* r8 l' P4 k5 Y9 L) Q" {$ ^; F. B
iDataNum = recv(client, buffer, 1024, 0);
: f7 n& t/ ?; O q: b2 Q" m5 C0 H+ ?' c6 J3 P9 t
if(iDataNum < 0)- h' \9 W+ _, j
9 i% }* F1 w$ h) b) F
{6 v' X: @" e, A; |/ b: I, }
& s! o$ h7 T% I& w: P* u
perror("recv null");9 K, r @. o* B" ^ ]# F
5 s$ T2 ]+ n( L$ t, B' M& Q
continue;
1 W6 q- {" N2 T& a) f
1 ?8 C" g0 X8 ^, P}8 Z6 Z- L% f) ~8 b; j# K3 ^
. c+ b% _" K: G5 b: Bbuffer[iDataNum] = '\0';; C* K6 U, N, T3 q
" Z& m9 P3 P3 Q- i- @$ `
if(strcmp(buffer, "quit") == 0)3 t X- B3 \5 x+ }% R! o; I
0 F: q" S/ J+ v9 F I$ Y8 T
break;
. e9 l7 ] _0 `) F# b2 o& T7 Y; k& P1 R R8 {: } h, R
printf("%s\n", buffer);' C! T& A# G* w1 L
1 H3 x+ O8 ?# { C
]6 ?7 m6 B- j5 v2 }2 R
! v6 [6 d& F. }( E/ gprintf("发送消息:");
( F a+ M* a) A0 S, Q2 n, f# P1 I$ G" C( T5 d, i
scanf("%s", buffer);4 R/ H1 Q A5 G- I' Q- W4 ?
. ?& l {! @# U' a; p M! Cprintf("\n");
A( w) F% t) T. @* s+ } ~, x
: N. v) c. \9 u9 W5 {8 bsend(client, buffer, strlen(buffer), 0);
/ F) s. ^3 T5 K4 p! o
3 Q* G+ I: e- e$ K8 \* F2 Zif(strcmp(buffer, "quit") == 0)2 z" v- _) _5 S
5 v) s, N6 O2 h" O7 F6 Y: e7 Q5 ubreak;
: B5 `, u3 U" m5 f8 [& x! Y* `* C7 S) Q/ t6 |. F
}
1 T" l" w3 n- M- v) Y* v' T. E% [
}
$ B T' g/ t3 m5 J, V" _! e; k) P$ P* k) w: b) X* v
close(serverSocket);
. R- F# I# k4 H6 ? H) K* X8 ^
9 K5 f! A+ ]" T4 P: Zreturn 0;
; ]& ~# T, h/ Z1 l7 s1 q3 c5 r. N& `2 M4 T
}
. D' r' Q- Q7 ^% A! H+ gclient.c
+ L! ?. w8 N- |9 O* X, {#include <sys/stat.h>. c- `' h2 R. s" x2 L) _" u8 c
6 v2 X7 H& A; y% e0 g6 |#include <fcntl.h>9 D, ?3 S! o# Y+ \) F: P" n
2 X4 Y1 k7 w. y8 r7 w" w6 E/ [ V#include <errno.h>
4 k' Y! T* ?2 w
$ y' z+ L+ J2 L0 D#include <netdb.h>0 b3 x0 y/ _ s
, a: I/ C& ]) Q( y; }#include <sys/types.h> @4 O8 b7 b" L; B2 X
# M9 g O2 C. O9 _#include <sys/socket.h>
) A' Z! U) Z& b# O5 O; w- F
. g& O# ]8 h0 p, I#include <netinet/in.h>! q9 e# @, m+ X! s2 x
p1 E; N- m i) ~# g$ a7 F5 G#include <arpa/inet.h>) {; B% d% t' c1 L
4 w4 a+ [" y" j2 Y2 ~. L! e \( W
#include <stdio.h>% K& k) ]1 }% o
$ M0 B6 S3 }: O! }
#include <string.h>
. n) t1 ?: I0 O6 p8 y+ P1 u2 j& s3 V; Z. k% A8 J
#include <stdlib.h>
& p$ Z' ]# O* L5 B5 F# n6 ?# c" k9 k8 N; n
#include <unistd.h>
& z' J ]0 q# O+ W% T- ^6 a* I/ T' R+ r$ M7 k* F4 r
#define SERVER_PORT 6666+ r ~! N8 k2 s& o; M5 H% b+ m; {7 {) [
8 ^/ m7 C! `! m( u0 b! T2 \
/*, Z( A6 ~$ Q3 V5 @" L h3 t; x7 E
连接到服务器后,会不停循环,等待输入,
* q+ E7 f" }# Z6 a输入quit后,断开与服务器的连接
$ G) G0 L1 t6 Q; M! B( c! S& Z* C*/7 l: ^! m/ a; S. V R
! m/ p' v6 V4 I$ i. x% ~int main(). u2 V% q! S2 N6 _% E
: u. M3 z0 p M, E, o
{
2 b2 S, O+ D% q! J
" z# b7 r% h( r- `" L) j( ^//客户端只需要一个套接字文件描述符,用于和服务器通信
2 N7 J( k3 {# S+ a+ \: s2 ?+ A3 s/ h2 i! b) @0 L8 n
int clientSocket;
; e5 _; {0 a9 H3 R0 ^
! n- P6 V) q) {9 a' q5 f }//描述服务器的socket
) j: \4 t2 V. _9 w
. U! [' [7 o5 p* z& Rstruct sockaddr_in serverAddr;
% m, J6 `+ d5 F, a6 Y# [1 T! j h; `' H1 C0 t- c$ g
char sendbuf[200];3 E2 s. P: f3 e& S& U! a
( i1 Z! j0 N/ {
char recvbuf[200];
4 G4 k! k0 |. D3 o" E
+ P$ q3 F' j) V0 J, V1 j6 X! |int iDataNum;
' I4 ~8 s: G0 D [" ~, T- V2 J* T! i h$ q
if((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)# A. U9 ?: E4 d0 g3 y
4 K& [: i& X# s5 ?* Z# p{
- h- E# b {7 Y9 q4 j
2 j/ a, @& M+ B* v) k0 |perror("socket");
2 Q/ L2 Q0 I' n2 V4 p( I3 r0 y+ ], T
return 1;5 [8 O$ G) K- o4 `
! B) x. I0 t. |! o7 d
}
) ^! N5 x8 D( A+ `! N3 [, M+ R6 E' a# Q6 f5 Q
serverAddr.sin_family = AF_INET;
; a" u3 R8 R8 H/ v6 A- d8 O2 I8 @. r) p7 z6 {- j
serverAddr.sin_port = htons(SERVER_PORT);
0 r9 U$ Y I- s2 U) Z9 d$ L& \, n! a, Z" }1 x
//指定服务器端的ip,本地测试:127.0.0.1
. k+ ^2 { Y( h- k" z6 [0 ~% P/ l; W: q- k. y/ _& U
//inet_addr()函数,将点分十进制IP转换成网络字节序IP8 {) `7 a Q4 Q
' X8 _4 N1 m4 u) l5 jserverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");& n/ g- ?; [; G, t K( X. ~% c+ o
6 U1 O4 }2 d6 E2 q! W# k7 oif(connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
) V# m8 {* I T8 X$ c( @4 `" b+ [4 |7 B. V3 W8 k" g
{
: K/ U! \( J# L. K7 _5 z3 u
# m- a: x( S. T" W" D+ R4 `! aperror("connect");7 \+ z. {2 c: a7 `7 z% h
# o8 t! c5 u1 Hreturn 1;
9 x4 g' h4 ]8 v7 @
# w+ `: J0 ]- B6 V" @( P}: U/ Q- B9 D, J% x' j: f9 S' J
4 n% c, y! ~4 R) g3 lprintf("连接到主机...\n");
+ u# m9 v3 G4 { @% C! a f6 o L' ^1 W3 w. p2 y' J
while(1)
5 g: b* |8 n- ^5 `8 [7 o0 q0 q: V* ^1 h
{* i9 S* D* E" e( \2 b
/ |2 \* r7 Y4 }8 w. c0 g# U( p
printf("发送消息:");3 P% W7 C" s" t' ~9 I
: `( d% h$ {9 B" n
scanf("%s", sendbuf);. d) y7 v# L! P! R' C0 P# y; P& g, }
5 |/ h( r G5 `5 U# V; e/ s
printf("\n");
3 u: |7 A; L) ]' v9 B' _! u( \6 i8 M' s4 h7 _' T+ E
send(clientSocket, sendbuf, strlen(sendbuf), 0);
! e3 _% [0 e( D( x, n% B0 b8 v* l7 T7 A! q n8 a$ R
0 ^% \+ N) {% \6 U9 U6 X2 j( h6 a% I) S' z
if(strcmp(sendbuf, "quit") == 0)0 O( c1 H/ M0 E, I% V
5 U. [) u8 y/ h- F3 |
break;* g" M1 C$ b! }( b, L1 @/ q- `
& ]& e! C# y& n& Q8 c# `
printf("读取消息:");6 W' z; g" N1 { @/ y3 }% @
) z% n( R. r( l" A2 p2 O
recvbuf[0] = '\0';8 i4 ^" X$ e- ?& q% Q
+ P) Y/ I4 T/ h1 i+ K
iDataNum = recv(clientSocket, recvbuf, 200, 0);7 p. K( |- J( W L9 \9 ~; E
; P- D7 K1 n6 e4 W5 X
recvbuf[iDataNum] = '\0';- ]2 L& E" @: |1 F/ z, ?$ i
6 |, F6 K* A9 c: N" o! g; aprintf("%s\n", recvbuf);
( S& Z7 T! `6 R" J& j- n0 i! o) g" C- x
}
- g5 e1 S9 f# ?% K. B7 G) h) \% n7 @$ g2 Z7 m2 A
close(clientSocket);
, j0 x% G2 Y2 |; j4 ~6 S! n6 I
+ W, M1 R: L' q( A- N! m' ureturn 0;6 U5 p9 M, \: q2 t
5 P: ^8 G1 B: t/ x
}
1 ^% L( f$ _7 b4 ]5 ]3 F9 o
" [/ C+ r! |! e4 m |
|