找回密码
 注册
查看: 479|回复: 0

C语言实现TCP-IP协议服务器与客户端互相发送数据的socket编程

[复制链接]

1

主题

0

回帖

12

积分

管理员

积分
12
QQ
发表于 2023-6-26 15:34:11 | 显示全部楼层 |阅读模式
C语言实现TCP-IP协议服务器与客户端互相发送数据的socket编程9 T1 F  P0 ?# @6 v- n

/ Y7 g$ r  q7 H4 nlinux下用C语言实现TCP/IP服务器与客户端互相发送数据的socket编程  ]) R) C/ a1 |0 e5 Y
+ p. F0 u  `' k
server.c& W6 |- z, l) F
#include <sys/stat.h>) u0 E! y& b% ~$ F3 x
& w3 w$ ?" m' H" }% W% q
#include <fcntl.h>( m$ e& I9 J! a# ?

  o8 D, }3 K: v" _: J2 [7 g+ B/ |#include <errno.h>  c) Q: P* W+ i  j$ r
  o/ C& l5 P, x6 ^* T
#include <netdb.h>+ w- E1 l- a  w

+ \3 m! k! P. R& W" |& t) C#include <sys/types.h>
; [, B, y/ E! s9 q6 j) W9 x. `" s, e1 J0 e3 d
#include <sys/socket.h>9 J2 ], M" A7 j
/ z& X' O. F6 E( s8 a
#include <netinet/in.h>
4 r7 H" s# O, X7 \! G# \6 I: K; H. l1 i3 L2 x
#include <arpa/inet.h>
9 \, l" }- s7 w- g
! [! N: d6 Y: |+ v6 Q#include <stdio.h>
* U4 H1 }* m% Z; T' }9 y  P! a0 `! f5 p: K
#include <string.h>; D2 c3 l3 V. S; ^

- S! Z% z+ H, y, C2 n#include <stdlib.h>
. b7 \7 C/ J3 {9 V9 L, [6 o5 {& q  ^3 j/ y0 w1 m
#include <unistd.h>
' y: u3 D( e$ D6 j2 p" ]7 Z0 {$ e
- C; g' I, o, |/ a#define SERVER_PORT 6666
2 H, w: R0 X: _6 u) r  l3 |6 E/ h6 s: G% a  Y+ c8 P$ I
/*
3 V/ G% @! K. z% z$ [1 I; ?( ~% V监听后,一直处于accept阻塞状态,1 {' r, Q) J/ U- L; [. G; l
直到有客户端连接,
" r  `2 A0 \: H) f# f, w( t4 [当客户端如数quit后,断开与客户端的连接- L! l  R- m2 \6 o
*/) x! x' [& ~0 [1 a- ^
: ?' ?$ Q* E' P1 k& B+ Y
int main()
" |9 X; r; p: u0 x
$ ]' i) q. u  @{
! G6 T( N/ V% `/ X! ~( ~5 S8 T+ z$ U. O4 p' Q+ X. y5 j
//调用socket函数返回的文件描述符& h! O5 u9 ?, ]: N3 O
6 M' x5 @, [) H0 `3 }$ W4 a* a
int serverSocket;
' c3 u, K5 S& {! \' m4 F1 g
4 b5 r4 V9 `2 E5 y, F  l) w//声明两个套接字sockaddr_in结构体变量,分别表示客户端和服务器) G* _# q; h/ J! G

# G' n8 |7 d3 Y3 |+ zstruct sockaddr_in server_addr;
- }2 Q0 E0 b! i+ F# V: F0 ?
( u0 {5 |+ x) F/ k' v7 A/ W0 hstruct sockaddr_in clientAddr;3 ?2 \( D2 f# F7 R1 S! s" Z
" W* x. T& O, l8 o& R
int addr_len = sizeof(clientAddr);
$ Y: \4 F1 G7 O% M! U( N
2 B4 o, y) t. P% tint client;; G% F0 t- T& Q- q  {: S
+ N) U1 p$ t$ P0 F7 r
char buffer[200];) |) @9 I- I* q5 h- @  ?- u: X6 M) A
( k$ a0 l! W6 H% R
int iDataNum;2 M( C: g% v' \# n0 r' v
6 {# E5 ]' O% i! @
//socket函数,失败返回-17 ]* g% r, l2 }; X+ [
% y6 ^0 S; j  ~4 M, C& @
//int socket(int domain, int type, int protocol);, S; c% u7 z9 \* `! a- M

' S/ x4 ~( U1 _' v4 h1 Y//第一个参数表示使用的地址类型,一般都是ipv4,AF_INET
6 m  Z" Z& k. @( f, \! D" ]. o- e. x
//第二个参数表示套接字类型:tcp:面向连接的稳定数据传输SOCK_STREAM
- D; k* e) }3 G% k
. n, Q2 T2 b7 R6 E//第三个参数设置为0
5 ~2 s- o+ M; v, [5 T; _6 V6 p' \. H
if((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)- u7 o2 c1 _7 Z0 w/ p4 b
, M2 c$ K' m( b/ o4 |; Q
{
9 Z: ~  L3 h1 |: U- Y( Z
* q( l" p; f2 I) L4 V# a" zperror("socket");8 ?" k3 ^* @3 z/ E+ F2 W: Z

: h) f6 Z; h2 h9 |1 Oreturn 1;
/ ?" \2 n6 d, f9 g% B: n
8 u) w- _2 r5 q}
& M* R+ r7 e/ d; ~6 a6 M! g+ [- r3 E
bzero(&server_addr, sizeof(server_addr));/ h5 Y4 B/ y( b

) ?# I2 j5 @2 Z+ w- C* z//初始化服务器端的套接字,并用htons和htonl将端口和地址转成网络字节序
/ N+ k! r$ Y( s- \4 E; K* f! t
/ Z) u' [( e* K$ s; lserver_addr.sin_family = AF_INET;! d; p' T  Y: j3 W5 c

( h1 h! [& P! f$ Z( {% a6 F( \/ Eserver_addr.sin_port = htons(SERVER_PORT);
( n- i" L' n( |5 K, z4 I$ C$ R, q' y1 w( a7 ^
//ip可是是本服务器的ip,也可以用宏INADDR_ANY代替,代表0.0.0.0,表明所有地址7 }' W, t6 g, W7 Z; w
* z# L8 m. m2 ?: E! m( \: h+ o
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);: W! B, q; {+ S& q  L' y

) Y9 t. P8 ?( T//对于bind,accept之类的函数,里面套接字参数都是需要强制转换成(struct sockaddr *)
, H+ q' l% L; {3 L. k( G" X* ]. F  f0 X) m9 i
//bind三个参数:服务器端的套接字的文件描述符,, F/ [7 N, r, F9 u
& I1 ?  c$ i) v) |/ r; ?
if(bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)* S0 ?' ?2 G' R% V1 s' \! ]

# ~0 `$ T" ]- q+ C) z  T{
  a# K+ k4 B/ n; L# ?, u+ `) i9 b0 d+ a* ]4 q7 h7 x
perror("connect");
, X% o( T$ `' n8 @- u
1 ^! }. Z# x: f0 E1 A+ Jreturn 1;
0 `8 ]. A0 ]$ x
3 V) r5 C1 C& C0 s}
6 q/ H$ A) [+ V9 y4 R
* b0 w& A  g% B, s6 X9 W//设置服务器上的socket为监听状态
3 {4 ~3 a: P* W1 {  \9 `1 m- f% C- M& K! t: L1 s# K- w* i/ B4 F( v% t
if(listen(serverSocket, 5) < 0)
: Y/ b, d' K$ }& p) a
/ t2 C( n2 p0 r" S7 J/ _{
0 W) F, ]" t( D, ^$ {
5 o/ x1 a+ F- zperror("listen");) w1 I. e8 D/ ?9 M. J7 i4 O: o

* ^+ V' w4 J- K: V, Jreturn 1;1 b7 u5 b2 S0 s+ _% x

, V% w0 B, s7 F! ^8 H( e4 l}
6 Z* a: m* D' r8 ^" x2 \' v4 A7 o$ D% b3 v
while(1)
% L- `0 G4 ]$ g. Y9 B- X
. O# t8 B. u2 ?( a; Q; W: t{( M5 q0 Y% D; B
. o, C  X: k6 R3 i/ K
printf("监听端口: %d\n", SERVER_PORT);7 P7 `& f* `: e8 S) p
2 M' Q/ h, x- Z) [; Z
//调用accept函数后,会进入阻塞状态9 @- X0 x* Q2 H

+ h: e$ l3 M1 `) s8 s4 g1 ?, s//accept返回一个套接字的文件描述符,这样服务器端便有两个套接字的文件描述符,8 b% \1 W/ c2 c) m
( r( m  m; y- {" y6 m
//serverSocket和client。
! A  E. X) V3 c: y1 s% E! v6 \3 z/ q( ^% j* A. X2 n: U; `
//serverSocket仍然继续在监听状态,client则负责接收和发送数据( Z# L+ Q. Y% y

: l9 o" d3 H! K, w+ O: q7 b- X0 z; N//clientAddr是一个传出参数,accept返回时,传出客户端的地址和端口号! k, U9 D4 `& A; p1 u

2 b: b; [% n1 b" o$ a. S# q5 \//addr_len是一个传入-传出参数,传入的是调用者提供的缓冲区的clientAddr的长度,以避免缓冲区溢出。* L5 b1 s3 o9 \& z

! w) Y1 Q/ O( Y  ^; ?- e5 d//传出的是客户端地址结构体的实际长度。
' S& }& e+ e$ C) n
9 b. R$ U8 `, j* r! N0 c/ F5 z# G$ t6 y//出错返回-1
% \! b4 u# d8 Z. C/ d4 o% K8 ^2 f. P5 q( b2 C5 |4 a9 J0 F' a
client = accept(serverSocket, (struct sockaddr*)&clientAddr, (socklen_t*)&addr_len);
9 T) j6 X/ O) o/ u0 ^
8 p8 c) T& Z9 {0 r- {if(client < 0)
* {; H0 e: Z1 E
, M0 [/ _; R+ M% J0 x{: l6 l7 i$ L5 @7 I$ K; X3 f. n* y. g  r
% I5 N6 _2 o6 Y. s5 D
perror("accept");! ~5 X8 N2 n' `- z

1 m% C; i. l. c6 lcontinue;3 Y1 I. S3 E" W6 O0 {

! n) N3 `/ Z6 ~}: ]3 T3 g3 x0 @9 j) q
1 v. W+ c7 `% y& _
printf("等待消息...\n");
) K+ ?" d) |6 [6 }. w6 b% }2 F) b8 u1 ?  R3 s3 h
//inet_ntoa ip地址转换函数,将网络字节序IP转换为点分十进制IP
( H8 U2 Z2 }& D1 e/ z3 S' @7 ~" V2 v- Z
//表达式:char *inet_ntoa (struct in_addr);
& ^$ y8 }3 a8 c6 M9 Z; z5 v! V# m7 ~6 D5 U% T" \; j) [
printf("IP is %s\n", inet_ntoa(clientAddr.sin_addr));
0 n2 i* k1 y4 `1 [; _" f( }5 v: x& ~3 {3 E" F
printf("Port is %d\n", htons(clientAddr.sin_port));
" u5 B* W' `; b& B2 R7 |1 v
" r, F. o5 V% v! V9 Bwhile(1)  R1 Y/ E! b6 k# ~/ T, \, _
. X* F" s! N  W
{
$ M! P+ R" v  ]. K% a. O- Z# ?8 d* Q* b
printf("读取消息:");0 C* K8 o, L( s9 O

' F5 S3 w# l$ a0 f2 jbuffer[0] = '\0';' @7 @% S7 k" T, \& O+ p8 I' K4 m
/ _( V  G; `2 Y8 m5 i
iDataNum = recv(client, buffer, 1024, 0);
$ S2 h  c' M9 c  j" ]
. H, `/ f! d' [( b: h' x: h8 n3 E  dif(iDataNum < 0)
6 N$ K- T8 k" f& K# Q- {9 v( x$ L+ P8 s' y
{: [! q+ C+ J- l. Q+ d3 L" T. ^
* Z2 g' }1 `! O* d0 R- L
perror("recv null");- K" e9 A5 h7 v! v) l! {9 ]* ]

6 ?8 c4 I4 Y7 ]+ P6 O- v3 hcontinue;
5 h! ?2 K) R0 n6 _8 b- K% I7 v" U/ d: g
* m" |5 i- C' a}
( ^1 }% C% s& u9 p+ x$ M5 k, c
3 z7 x1 {; N2 U5 \buffer[iDataNum] = '\0';
' z" ?  }1 C" V. _  [
% s+ ?9 R8 |) p" Eif(strcmp(buffer, "quit") == 0)
$ E' e# f3 r6 ~% B! i, z% d. j  {4 L6 Y/ Z
break;2 Z4 d+ ]& _- I4 u/ X) d- m5 W0 m" v7 J
) ^$ \" Q9 {' p3 e2 ]) A
printf("%s\n", buffer);
: f3 a* r* i3 W$ V1 J6 F" k8 \: S0 d; d. T
) G; R) E% l1 q* y

4 u0 B4 X- T8 y) y" qprintf("发送消息:");+ j, T9 S3 o# i
# ~) ~: M1 O5 ^* d
scanf("%s", buffer);
+ ^, ^' ^7 K8 q: W. `' ]+ W6 T3 w  w# I7 n8 a
printf("\n");* U. O  D- d- J8 |" z/ `

. K0 ~) o1 ~/ C+ g% r6 Osend(client, buffer, strlen(buffer), 0);
2 T' T& r# h( N/ g6 w& T- \8 t% G% x9 g, ?4 P) y2 k. Y
if(strcmp(buffer, "quit") == 0)( t7 l9 ?  C$ R3 V5 D

, m/ I  k( \" Z5 |+ t1 m9 ?; ybreak;/ W$ j4 A3 N- l0 y7 a

; Y. j" M/ `6 U) W, q}* O( c1 l* l) c/ d& f5 `) |: g

$ x* q( c" n! X# y2 E}4 [6 [# x3 j0 c! L

# D0 z4 {7 }, ?: B9 W( O0 U, Y$ nclose(serverSocket);
2 W) Q# P& C9 {! ~1 f2 N& N) L
& X  u; t! ?8 h: T( h. y% n$ o3 ^$ [return 0;
. D- p! C# f; j4 Q- y7 X6 o; [1 o8 H9 X2 _# N2 A
}  L! x3 i* V" E
client.c/ H. l; v2 j6 P! m/ [  H7 Z
#include <sys/stat.h>7 [7 W( V1 ~9 x1 u

: j4 h4 _- M5 o1 q#include <fcntl.h>: m; J( d0 [  k) z  R; p

1 y9 v. D- ~3 _' J$ q* [  _) P! ]' @#include <errno.h>" X' K9 @) |8 G& w9 `8 B

: X7 b  W4 k8 K! q6 D#include <netdb.h>  O" {9 ]# F) r$ L$ G8 A3 L7 S9 m
6 F0 c- z, V+ L1 a" _
#include <sys/types.h>
% i+ l+ U; k, j2 H' A$ |3 S( X5 I% J' ^1 v  p8 S- \! @2 `
#include <sys/socket.h>
9 A2 f7 n  ?, r* _0 ?+ |
/ n- U; P8 [% r. X, u4 R5 a/ G#include <netinet/in.h>+ G5 v. S$ G7 l! h
& E* P' c# r! K: J
#include <arpa/inet.h>6 e; @! i& T  j" T3 a7 Y, B% c+ x

8 V0 D2 E9 q; p8 T1 A+ |( i#include <stdio.h>
, B$ f" P+ N( [1 K5 J* Y8 N$ B' @4 N& d4 r
#include <string.h>' w; K/ [' L. n) O) `4 W# J  ^
0 x; D# i0 C4 v! \2 Z5 U: N. l
#include <stdlib.h>1 o& f, V+ x* |5 `8 j5 R+ z! V
. f' D1 M; ~2 Z2 A
#include <unistd.h>5 L7 @. Z# i8 w9 S+ N9 e# v
! k8 T- u( d- i: u" U1 `. X
#define SERVER_PORT 6666& ~4 O+ {9 x% D6 k: R/ ?
' V1 j- y0 h2 U9 ~/ H3 L5 [1 I
/*
  F. o5 \& @9 ]  ^连接到服务器后,会不停循环,等待输入,
) W0 E/ j1 b! Y( V( W' f# I0 w5 ^输入quit后,断开与服务器的连接: a+ L  ~! ~$ X# m$ \
*/
+ b6 ^, C9 a# p6 e( X0 w6 m7 b- E8 D3 p: y0 ^
int main()0 g9 g7 m" \' v
" G& w0 f2 H3 t8 G# H) c
{7 M& ~% @3 q& ]

0 \5 h! `5 q: X! i( p  f6 \//客户端只需要一个套接字文件描述符,用于和服务器通信
* \$ U& g6 u. K. `9 }+ e, P; T( Y; @: J: u. w. u* A' ]
int clientSocket;
% o. ^3 P" |- ~$ n. ?/ U, _8 h
& X! u0 ?& x" g' M//描述服务器的socket( `+ E: l. h$ J9 V1 Y7 [
$ v7 J3 D- H8 b/ t- K% B8 d
struct sockaddr_in serverAddr;9 W# i" l% D9 x7 N$ Y

/ u+ M! O) G1 o' u1 Ychar sendbuf[200];6 A$ z, R3 Y7 Y6 D; s( w* u9 J% D  H. r

5 q4 w8 K: E( ?: b2 ?8 ?- K0 Kchar recvbuf[200];* W  }2 T$ X7 M! J3 [3 j5 r8 @

3 }  A% o8 c+ J9 n/ m( kint iDataNum;5 y: x6 S/ H0 E  g9 z* E

5 \% T. R: L3 |) B1 p0 zif((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)7 z3 U0 I5 z( S4 c" j
9 x2 }. h, b* {9 G( x3 B0 v0 N
{1 ?! z- e0 T' Q

0 T( _! p1 o& ?/ X3 rperror("socket");
% d. G- _# K5 T: y: s) z8 j8 z" B6 B# D5 h
return 1;$ ^$ }0 F2 X3 ]3 t5 a
+ Q. ^2 Q$ o7 T1 O2 D: ^& D8 C
}
* v7 N9 C: w1 T: U& Y# \, c/ R1 ^4 V3 p- c# }" }
serverAddr.sin_family = AF_INET;: M% s* K/ x2 _0 ^

) C0 Q0 D% [8 I$ L3 E; i! C; l# ?serverAddr.sin_port = htons(SERVER_PORT);/ \, n# T) l" p+ A" \. J) o
6 a" P5 w, l8 e% [. `4 u
//指定服务器端的ip,本地测试:127.0.0.1$ m6 u4 V/ y* N+ A+ U; B( L

' N. @( r- L7 c! P' t9 g! Z8 v5 }//inet_addr()函数,将点分十进制IP转换成网络字节序IP! _& \! d4 H. y% W, l1 O. `

4 ?8 s% H% ^/ m. M1 H1 lserverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");# B$ J0 T8 A' K$ L0 e7 f4 ?
4 E7 M+ V0 x, A' L4 c
if(connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)( J4 K; `6 \/ @6 i" g5 ~

  e2 s1 n$ D* Y0 K/ H4 f4 q+ a{
% K8 o3 `2 o/ {- p  W0 S3 q6 i, a/ w7 f" ?
perror("connect");/ D1 k; t3 \+ |  F8 L9 q* V

- q* g) G+ a, J/ c6 J4 `  ureturn 1;# l; I' Z/ h0 P

4 Q* l. F' x% _, _! `}
  l* E5 j& c2 @" j9 }  ~7 }
6 ^, I6 K- X( U0 `6 Qprintf("连接到主机...\n");
- g8 V: L) w# l- D5 Z1 b' l% ?
6 R; s3 J" W2 s( C2 \( Jwhile(1)
" W- V( D( s6 F5 W
, R& M$ E, P# C* i{& {  c( n( {, a) t4 ]  B

+ e! q: c. P- U$ G8 lprintf("发送消息:");
) O6 O" h  e( V7 s# S$ i# ]: P: q3 u) C
scanf("%s", sendbuf);1 ^7 S! @7 j2 b, S2 a
( N9 Q3 q" K  k. h" H
printf("\n");
6 b5 G, F1 t9 P7 D
. L, W* t) A- Z7 O! \  Hsend(clientSocket, sendbuf, strlen(sendbuf), 0);: f0 N. z; I4 z( p# F- k3 O
7 @+ V  F1 v  f, v" T6 Q, F
* y: R2 _$ ^$ s. w, v6 _8 O
2 U" B( n# b7 c* c" W5 Q" L8 d/ H
if(strcmp(sendbuf, "quit") == 0)
% P& }4 f0 ?: Y1 N8 l" \' C" ?( t; A8 I% U, m
break;8 M* C0 S, v' G* I% ~

5 h$ m3 f9 ]% ?' ^" \$ X- Wprintf("读取消息:");, p8 l  P! n4 K/ Y3 f8 N* d3 w

+ ?+ G& r% K: x5 W- Urecvbuf[0] = '\0';- D8 @6 M1 ], [+ d

# o" {: O4 p# i# X1 SiDataNum = recv(clientSocket, recvbuf, 200, 0);6 G& X) [2 O- x) u; Y" D% T
) r6 i: f- O3 |2 i1 d6 d! n+ W! |
recvbuf[iDataNum] = '\0';' P* }& y3 R* r

  k9 x$ e# j/ j6 d4 t* S' Rprintf("%s\n", recvbuf);5 Z- O; K  e( G0 V( }

7 F( {& _: j+ }& z/ `}
( ?1 L) N5 |2 ?0 p* ^( A' w2 k( w# s4 T3 T+ k% S
close(clientSocket);% O/ Q% N% |& x7 A- I

9 D" a' K. K  M" Hreturn 0;
. O$ C, F" n1 B. I' n. g4 ?9 K% ^% F+ `* Q" q
}
+ R5 f" M. I+ p, ]% _# e' W! t0 l9 U8 o  t0 k/ A+ l
您需要登录后才可以回帖 登录 | 注册

本版积分规则

返回首页|Archiver|手机版|小黑屋|易陆发现技术论坛 ( 蜀ICP备2026014127号-1 )

GMT+8, 2026-6-11 23:21 , Processed in 0.017718 second(s), 23 queries .

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表