- 积分
- 16841
在线时间 小时
最后登录1970-1-1
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?开始注册
x
C语言实现TCP-IP协议服务器与客户端互相发送数据的socket编程
" B6 D: ^$ R) L
; d. W/ t- y$ _$ J4 i, @! }3 h9 ^linux下用C语言实现TCP/IP服务器与客户端互相发送数据的socket编程
Z5 I, B& a; X4 a$ C, l! H6 Y( l; I0 z' K6 b
server.c
2 q+ M2 g1 ]: f c#include <sys/stat.h>
, c9 @- S z. e. j+ Q5 b
. [, Z3 e- b1 l6 H( v#include <fcntl.h>
( _# V2 Y, ` r1 Z2 R3 W8 c% u6 [3 s$ } \
#include <errno.h>& C4 T2 L1 o6 t& J/ K: o
7 A/ \, Z/ N- q: p#include <netdb.h>: u, t. a0 s F6 _2 y; `
/ \$ l$ ~0 W& v4 S#include <sys/types.h>
4 K! o7 r+ o1 `, {% P* C- f4 A7 g* b: j
#include <sys/socket.h>4 [8 d, @, \0 ^1 h- P& K, I5 _; X
" x3 {- V% [3 I: Q) n#include <netinet/in.h>8 @* a9 w( l2 S4 O8 |% Q/ @
. j1 e& L9 W6 u' W1 ]6 E
#include <arpa/inet.h>
- w7 ?" k6 N+ o- `- L; g7 n$ |- E+ f. N, S
#include <stdio.h>
# x& C. i8 _, r/ F! c1 q
- z/ {& g; x$ [0 g3 K4 y#include <string.h>) S1 W2 _' ^( F
: I1 J3 v% t4 o: ?0 ~, y' U1 ?. S* H
#include <stdlib.h>: d- |. E& r7 K7 B2 W$ _9 j2 B
. s3 W7 x: ^, u; ^# y& R/ N#include <unistd.h>, r2 E9 i2 U$ }% O. k: |
! ]( q b- W- C ?8 W. @
#define SERVER_PORT 6666) w. ?! Z7 Y3 `( A1 E$ i( S3 j# B
% J0 R% q" d# }$ ]2 P/*, L4 }$ D6 w% T" T* f- C" }
监听后,一直处于accept阻塞状态,
$ S7 i) d. A+ M4 f7 ?直到有客户端连接,
- l5 U/ N; }) c& R当客户端如数quit后,断开与客户端的连接
& f% r I6 u/ Y4 j*/
& X4 t1 j3 v P7 {8 f z6 n; O0 ?! f- x
int main()2 [: }5 m7 W7 C: i- {
4 d: N' K2 O" q1 I9 V4 \; `{
$ S4 Q. M0 s* ?! w/ r V
2 S. V& F; n6 y6 f& T; q$ F, j$ w ]//调用socket函数返回的文件描述符! j: m& f5 K2 i+ F) E0 I; N
, n- ^$ Z; e' x8 ~5 N8 k
int serverSocket;) n7 ]! R: `5 Y" A: g i
) `# B, q- E' a- |- |8 x/ r) Y3 s# P
//声明两个套接字sockaddr_in结构体变量,分别表示客户端和服务器( ~6 E, X/ w! }( j$ T m
0 O$ f# _: P6 m5 o s/ Y8 e# jstruct sockaddr_in server_addr;6 R) ~' o: O$ c/ {3 s, L& F1 }3 ~
4 I. s' M4 ]# J+ H# H0 ]struct sockaddr_in clientAddr;
2 W% ?9 F, ?8 o$ T: l$ S( g) W' p0 M. B2 ]# }! D. o
int addr_len = sizeof(clientAddr);7 V, ]0 J! M, J, O- E$ x
+ u8 Q% e5 V. Qint client;+ \8 Z& _6 q; Y# Q4 m
& ?4 R" {( K* ^' C$ Mchar buffer[200];) o3 \6 e# d% T1 d* T T
, r' U' d& j8 @
int iDataNum;
5 ^* t& a* |, T. u+ n7 L; l' S. m* ?- \6 x. G- S
//socket函数,失败返回-19 J' G7 F) \( w0 R( q& h& y
# g1 R. [6 A% l {
//int socket(int domain, int type, int protocol);
9 g5 C4 G& W7 [0 k9 W x7 ^
: k c- E. ~! {//第一个参数表示使用的地址类型,一般都是ipv4,AF_INET& s* f5 |% ^, \5 x
( {9 g/ @$ o+ L* V; s3 U//第二个参数表示套接字类型:tcp:面向连接的稳定数据传输SOCK_STREAM, t( Y5 i+ K! a; j T, P4 I
8 l3 ?5 L8 M) c6 j$ s1 `//第三个参数设置为0
' Y G/ P' h7 ~9 I/ w4 C( w7 n4 m" p0 X( E/ \; n8 x
if((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)" t( j( ~, ?+ _
, o' z! N& o9 G& B
{
- g: y4 q: N. C9 I
$ D) ?; b6 w: ]* eperror("socket");, ~2 J+ r) A- [: Z1 G
: ~7 h/ J0 D, `1 `# D* Lreturn 1;
: r: f6 }# S& k8 e" W7 h, O6 G2 p* K
}
v6 k# d' f; _0 r/ f$ H) V* G& p
# @5 {, @ j4 F3 `- ^9 Abzero(&server_addr, sizeof(server_addr));
/ C( c9 C/ z- l( x% E1 m+ [
- s, \* \& v: b) c/ r, _//初始化服务器端的套接字,并用htons和htonl将端口和地址转成网络字节序( m, ?7 j3 w8 _& N; a
0 A! G5 @+ q" @& t! U
server_addr.sin_family = AF_INET;
1 |2 V2 r1 b" b# @2 ]$ p8 ?6 Q2 y& }5 x# n9 k$ L
server_addr.sin_port = htons(SERVER_PORT);* w8 e. ?8 D! X
. i% F! x1 A$ R! A4 y2 |
//ip可是是本服务器的ip,也可以用宏INADDR_ANY代替,代表0.0.0.0,表明所有地址
1 r" q% ~ J# b) m. S) R7 r! } o- r! [$ o6 l# o) Q* K
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
* U/ T# a9 q1 n, h7 y
( i1 L2 `7 E" L7 |. n" t7 Y//对于bind,accept之类的函数,里面套接字参数都是需要强制转换成(struct sockaddr *)
$ P! a6 g, m6 U) f, b+ r6 w9 U& c! D# R3 U5 g u0 P( |# j
//bind三个参数:服务器端的套接字的文件描述符,
) h6 y' \* f8 G
; c& H0 Y! j$ ~* C& U1 f) A- nif(bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)1 Y" o/ l& _: `& z& c
7 l }% Y" Z4 z, ~1 a
{
/ U ?* R( y; J+ y5 R! K! r3 Z
* ^* G2 U: I4 j& E5 y) {perror("connect");; O. M0 ^1 ~. L6 K/ }6 i6 J6 x
) q% o+ `2 j* A3 r3 i$ ?% Q: Rreturn 1;
' p+ `4 X* c) A' r# N% r: c
% l x% w: i2 j' g6 r$ T6 r$ J4 g9 [& v$ B}
8 i/ v- a! L u# [9 ?
2 n0 f4 ^5 _% C9 G: v//设置服务器上的socket为监听状态3 n* [9 X) \0 \5 D
* \% C* q/ z1 k: m6 J' s
if(listen(serverSocket, 5) < 0)
) s, k) I. L7 f& ~" E5 [/ v% I8 H- K; J" E5 X5 ?* M, U
{ |* Z1 I( y% x5 L
3 K: z( j) X M( y( a( a, Gperror("listen");" s2 v* e9 m6 |) W. e% Z
3 v8 W" s, R5 h2 O( ]# I
return 1;0 n: o9 k3 b9 h- S, x+ q, g) F
4 U# @; d7 p% U& j
}% {& s9 y+ G; B' a2 M. V
' v& l: S+ g# B) h2 kwhile(1)3 ^' q% c) `2 a1 h$ ^
/ a) D, S+ V1 j2 E3 f) t
{' v+ m6 v- H ?! O4 k7 N* V! K
) e% v0 r! u' H4 Q( [
printf("监听端口: %d\n", SERVER_PORT);
: B% Q$ X# i2 I' J. o
6 A% X" H( s) s- |( t7 ~//调用accept函数后,会进入阻塞状态
5 V6 A' \7 C1 X. }: W, |- z7 g4 A6 ^2 J# e4 }
//accept返回一个套接字的文件描述符,这样服务器端便有两个套接字的文件描述符,
% q7 w4 b3 P: u# f+ k$ C5 p3 L5 z: U) p" M0 o$ L+ n8 D. B- ^& s
//serverSocket和client。- J5 j f1 A) C5 Y
& W* E3 K8 t2 l p$ }+ ^//serverSocket仍然继续在监听状态,client则负责接收和发送数据
" M/ @, Y6 y& Y; k, w" G3 \' `7 N. T$ _+ L) q: u
//clientAddr是一个传出参数,accept返回时,传出客户端的地址和端口号
; n. F& A" W9 l' z5 T$ z1 H8 ~/ ~. Z
/ f" e' s9 D4 B" ?; _//addr_len是一个传入-传出参数,传入的是调用者提供的缓冲区的clientAddr的长度,以避免缓冲区溢出。9 h+ M1 {( x8 ?
6 q, R B$ C! ?9 d- E; u; q% J
//传出的是客户端地址结构体的实际长度。
! S1 s" s% i" |( d) S) a) s% u2 k9 c+ b# d* l2 D: ~; R: u9 E* h, U+ ]* R
//出错返回-1
6 _3 P2 @5 K0 X* d6 L
* ~% a3 n, J" m V, w" aclient = accept(serverSocket, (struct sockaddr*)&clientAddr, (socklen_t*)&addr_len);
2 m) W' R6 J) T& u
$ D0 h* [) ?; Jif(client < 0)0 s2 b- q. e2 V* H* W7 i2 r8 X
4 V; t( H8 ~2 L2 f, S, l{
9 R D3 u9 C/ u& m j% P1 }2 j1 K9 `- d& z5 u# ^* j3 b9 k
perror("accept");
. L, l% @! G8 k; D2 m- J! V# W, X0 n8 c7 h( |* V1 t
continue;) |6 ]& `( o7 Z B
7 \) L0 l9 V. S' q! z0 b
}
9 v1 e& ?, i( g' t
3 C; K; L8 u2 y& v8 I* L2 Fprintf("等待消息...\n");
' g+ F5 _* [ x6 ~! I* n0 D2 Z9 ]5 S, F! A: f
//inet_ntoa ip地址转换函数,将网络字节序IP转换为点分十进制IP/ o6 y9 v3 L- y# S
- |/ l K1 ?& Q% K/ h7 i
//表达式:char *inet_ntoa (struct in_addr);3 n, }: E: S0 ?9 l* F6 r2 k* L
0 y* A! u3 `; E3 _# }
printf("IP is %s\n", inet_ntoa(clientAddr.sin_addr));1 ?+ d5 ?& I0 q% d, `
# O; y. v0 n7 H4 X# a. l
printf("Port is %d\n", htons(clientAddr.sin_port));
- L# S' c$ K: Z& J2 B
4 t9 @8 y B; cwhile(1). }# I+ T( F. Y# x
/ X4 ^4 _0 H6 C, ?$ [
{
`# p9 w* B2 }/ y" W
9 b- f# {) k9 p3 bprintf("读取消息:");
' v1 A/ t7 b6 z" U2 S7 Q- H6 {! v/ m5 W k! y; T
buffer[0] = '\0';
% e8 o I" y& U# D3 }2 R1 U% n" H8 V, C( T* }$ ~0 C
iDataNum = recv(client, buffer, 1024, 0);' t8 R1 Z) i; [3 |+ v( ^' V d
0 W- m3 m. b) z
if(iDataNum < 0). d8 S/ j+ T7 j6 Z
3 K- W# C5 Q7 y6 r! Y- ^
{
. N) d5 {& _' i- s7 z5 B2 h: A* J% V C! D* u9 A. W5 G
perror("recv null");
' |3 I' I: f0 E) O( L+ E/ H$ O
$ T; H! [( T- c7 Xcontinue;
0 j( n9 C) b8 U6 J1 h, }4 _2 r' ?7 P9 p
}
. j8 e* G C) n8 Y9 ^ R; \) D6 A' h2 X
buffer[iDataNum] = '\0';' D0 ~* X/ U) J+ Y- P: Q! n9 R7 d9 J
/ S. H' j4 s3 ?( g5 l P3 Vif(strcmp(buffer, "quit") == 0)
* _, _6 n# ` _2 ]% }# o5 o$ o) v6 ]6 o' V5 M5 s6 m9 r
break;
, F: F! M9 j2 j, g/ r( E7 \
' b" x$ ^ q6 ^7 j7 Oprintf("%s\n", buffer);$ z7 o, s6 r5 K" k" r5 q% X
. O& }* L, N7 O, A! n7 o; H
7 ?+ X+ n/ `* U! F1 P7 S \# r3 b: c
# ~* ]& `) L. {printf("发送消息:");
% x: k( \1 x: ?5 \) ]" T7 o( [( u3 N& x( A/ x4 {3 m
scanf("%s", buffer);' n$ q+ o8 a" n. y3 v
1 f! \- O4 _" ?: `! n) v, ]printf("\n");
, Y% g+ k6 U/ P1 U1 V
. f( T- P: S. [& Fsend(client, buffer, strlen(buffer), 0);
' G5 H4 v; O% n. D* H8 y3 D9 ~" q) G2 i+ s! l% G0 ]. o v4 x
if(strcmp(buffer, "quit") == 0)7 \; h6 c9 w$ W/ E0 q3 J: n
; Y1 d) H* ?2 a0 \2 x& W4 m/ G" o vbreak;' Z5 T: q# S. L9 Q" ^4 m2 | r% I
; C5 T" c; d- ?1 }- e: h; [
}# o, D+ @3 k7 ]4 g. o
( S8 Y. |2 J3 p. q& Z6 ?
}" j B0 W: k B( F( V5 R
7 S. w' N8 Z+ D+ E3 a+ m, Jclose(serverSocket);9 W, F" p4 X }
8 C0 b3 r+ ]: Q* Dreturn 0;6 v2 P" D/ w( e/ m. O k0 m: N
: o+ e2 t7 G4 J* O! \* c" a}! e2 i& A" }9 \& T
client.c! Z/ \- L; x5 j( D: |- [+ F
#include <sys/stat.h>- U' m4 e! J, p) J% U
, E( c9 r7 a1 E: ^/ O6 n#include <fcntl.h>
" ?5 ?( H9 I+ N& {8 w# G- d1 V2 k# C4 }' r) |6 D
#include <errno.h>
/ f1 H A: ]+ o; b
5 G) z; w- V' U. e* D#include <netdb.h>
. O; A/ l+ F) ~1 Y5 `3 A5 R# d5 e2 \7 I
#include <sys/types.h>
! n1 C8 A# R9 M
9 c6 q* S9 Q h/ k! U, Y, ?7 Y#include <sys/socket.h>
; E' n S* l2 G" ?* D& Z
- v1 @4 \0 X4 l: S" U1 E) y#include <netinet/in.h>7 i4 Y1 @$ [+ r3 b
& \- {5 o8 Z6 L& ?" z2 B6 U#include <arpa/inet.h>
- T1 I4 {1 I) _
, j4 a# b2 r. W- |% w7 f#include <stdio.h>
7 c3 o7 U# Z+ g3 F
5 L/ K+ t, s' Y' H#include <string.h>
% Q2 c- A" M' A; X2 q; D) q2 h9 r+ V3 q/ H$ w+ E& Z r
#include <stdlib.h>+ c0 M1 y3 _, `
' m7 Q& N0 g5 m! n F+ q* r3 g
#include <unistd.h>2 C4 H$ ]4 Q. ?% W
4 i& q7 H2 u) ?$ e/ [$ ?$ [: L#define SERVER_PORT 6666
9 p2 j. t! V5 x6 e5 o! {5 [0 N- ?) Z$ Q0 l1 c8 W
/*0 s/ C! g& ^/ h$ J% i9 N
连接到服务器后,会不停循环,等待输入,
3 _, e7 `" r: Y$ X3 R输入quit后,断开与服务器的连接
1 _3 a, a* W, E7 w" @. l*/0 j4 b( \: ~2 C5 O% [ ]) d, y
7 {4 {+ B4 T$ V9 jint main()$ Y+ F2 w' G9 _1 p( S0 }4 I
) q" i& M8 L! s{6 i. y7 z5 j9 a7 l7 ^' T- k
+ ]2 j/ P4 O @" m- G* h//客户端只需要一个套接字文件描述符,用于和服务器通信
8 M# s2 Y4 L/ R) p6 ~- j9 M1 J+ z: o7 `
int clientSocket;
7 ]1 i0 B% ? A# i, ~# g# x( f$ ~3 d8 u/ X7 Q+ x8 f. q, J. _8 Y
//描述服务器的socket
- L& O5 T R) v' x+ e C: S
% H# y s% Y9 J: \0 ]6 ystruct sockaddr_in serverAddr;* }" n5 m/ Q' ?# J& G8 h
0 c7 j, t- E- y9 i
char sendbuf[200];9 E @& w' |2 S% r3 _! I. H# N
% o$ N& }! n" s, }" Y/ S- @char recvbuf[200];
$ ]( q% H N4 |0 I6 ~
' d) E- G' @9 h7 e+ Zint iDataNum;
; V" M3 K0 N8 n( C' ~
* }/ e* U8 Q r3 ?- Pif((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
6 g! r% T; I0 f& @- G/ Z
1 B) a4 j" g G4 T! ]{
- @3 W( J2 r# C( a/ L# k) I; ^2 W7 P+ w" `9 Q6 g6 v4 j7 t
perror("socket");
9 a( F8 J4 {$ [. M x* s; E; f c5 h t- P3 E
return 1;
) ~ y5 j* E4 y! Q
7 R5 _3 I& F- j9 [3 H* i}
2 ` w1 L% ], w: x
% Y$ ?/ g# N# {% d& @serverAddr.sin_family = AF_INET;! a# A5 g2 h" Q6 H2 u
. f: W$ v0 ^1 O) U; m: |& G# f; P# g
serverAddr.sin_port = htons(SERVER_PORT);
: H3 ?, s& |( E+ n0 @) o4 H% d. g6 J' q7 G2 Y& T
//指定服务器端的ip,本地测试:127.0.0.1& V/ W3 b- i4 i' Q, W" R
1 R! Y% A* e( ?$ F& R# b' ?//inet_addr()函数,将点分十进制IP转换成网络字节序IP
8 t4 k/ o: O5 N" F) e; X" T
4 c% T0 J$ G9 q" k; n( m; S# xserverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");9 ]( l; I" d. i' f
, Y Q/ o; \7 d3 q2 k! z5 Wif(connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
R' _/ Z. x5 K3 ]4 O2 O" P
C9 Z8 M0 \8 V& h0 k) X{
) A- F+ M# a" Y: E' W
* R' b3 a1 A# J3 l& \ `/ Aperror("connect");
. n% y1 y' F* }9 } N& T6 V, {3 \8 G9 l
return 1;# _4 |0 s4 k+ S+ ]! R& P
1 Y. N1 Z5 s6 P2 R; y9 n}
- `! c! t* |+ N! K, h( E8 C* ~6 V, c, o; B+ v6 L
printf("连接到主机...\n");
! W$ \0 x% D& b( R/ x6 V* l4 ?! s& y* }# k# e
while(1), p1 j8 V# X0 O
: U4 u& O0 { P, }* S4 ]{6 x( H5 i2 j, ^2 p; a! ?
2 w9 |2 a7 g. h! Jprintf("发送消息:");
: b4 [" {4 c8 L' O0 B
+ a% {- a' b6 a# j! o1 k8 u- j2 `scanf("%s", sendbuf);& f C: T, W# H! `6 W f
5 S: _# _3 F( p- [) v9 tprintf("\n");
- L* B& I8 s+ b2 X. e0 x5 R; b
9 D+ Y: W! F9 psend(clientSocket, sendbuf, strlen(sendbuf), 0);5 _3 y2 u. s. J$ h2 E
7 B+ N: [% n( o' N, v# r6 T4 X! R( W: R% G. u
' j# S% D7 A3 V: rif(strcmp(sendbuf, "quit") == 0)
% J' X3 x( M. ?4 |- m% b' \
6 ^+ t1 X0 X4 K( J# y8 b7 E0 W3 q6 @break;
p( D: x4 m, }" d: d" v1 J, V' p. M ]6 X% |" y1 D+ _( ~
printf("读取消息:");
9 f& X9 Z$ ~1 j. L( M5 F; B" h' J5 ^% [# Y& _3 w
recvbuf[0] = '\0';' W! P# E8 S* X6 Z
% y! Y) f* L) ^iDataNum = recv(clientSocket, recvbuf, 200, 0);
8 G2 H3 S6 j' y! H) h! v+ k' t- z1 ~7 B2 z8 h* {7 V7 A
recvbuf[iDataNum] = '\0';
8 l) s) A1 {1 O5 `" q& f7 U5 W' e+ l' ?, v
printf("%s\n", recvbuf);
& e8 w% X& A0 W! a s; L
+ E* i0 j8 N; q @, r l, g}8 C, M" Y7 u1 A6 X. q
$ q: F- p# A n/ w( bclose(clientSocket);* c$ O* `6 O: b& W9 M% e/ Q& _; _" l
4 {8 f$ o5 S {" Mreturn 0;3 \& ^- i& A5 L" N6 w: ~. I; J! _
, ]3 `, a; Z* j}, {6 t) v$ ^7 m7 v+ X! W6 m: C, ^
3 c8 K- ] I, s |
|