易陆发现互联网技术论坛

 找回密码
 开始注册
查看: 471|回复: 0
收起左侧

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

[复制链接]
发表于 2023-6-26 15:34:11 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?开始注册

x
C语言实现TCP-IP协议服务器与客户端互相发送数据的socket编程
% _; v! K- ]: v1 o$ J1 p
& u$ M3 Z( Y1 m
linux下用C语言实现TCP/IP服务器与客户端互相发送数据的socket编程  L0 \& t/ [2 Z4 H9 X
* H8 N1 u  {0 }) l. X6 S
server.c, j/ k: |1 w4 Q
#include <sys/stat.h>
* E+ J* r7 p/ M, X0 |' I7 z+ Z
2 [; M; r' J1 U; E; B#include <fcntl.h>8 ]. |1 E; E. t; x$ b

0 G5 h" z2 p% ]5 u) f, {#include <errno.h>
, y9 E+ p# ~, M& _, K/ C
# n7 U7 Z- _! E, r$ @# k8 ]9 i( E#include <netdb.h>* m8 h# k  H/ O
) }; X7 {8 x, p: u; U3 Z! n
#include <sys/types.h>
6 r" c4 K/ v9 M. N5 j
7 M# N; R. s; k0 N/ W1 F; a+ f#include <sys/socket.h>
* o# Q' q; }; V" H: s* b6 u$ o
9 f3 ?; S5 c! D1 c. U; ~#include <netinet/in.h>
. m- o! O$ v2 y1 K( |, H
& C* b+ @" Z, Z) C: @#include <arpa/inet.h>
7 V: E3 f5 J% J# b# ~( o1 L$ E$ N: W: r
#include <stdio.h>+ b, q7 R1 O7 G
0 ^4 e! B; |; F: A+ j/ S
#include <string.h>
; b7 d7 \  w$ E! ^. C/ ]& o9 f
6 w4 E6 H1 u; @6 P#include <stdlib.h>1 T6 V. P/ i! L! _
& Y* z: q& B( s  K% a/ P2 v
#include <unistd.h>/ }& b- d, W8 i
0 v8 F( Q! K1 q2 |
#define SERVER_PORT 6666
* w2 i5 X1 w; X5 S  Q
1 Z7 w# @: @9 Q# e' m/*
- [1 U1 @7 k8 t. Q/ A* ]监听后,一直处于accept阻塞状态,0 A0 f6 [+ `1 j6 {: H. F- g
直到有客户端连接,
# u, t; [. i4 L当客户端如数quit后,断开与客户端的连接
5 B5 s9 l$ T' M*/
7 `2 E# p( J' h1 R8 M7 K' }% L( l2 T: W/ i8 D! n" a
int main()
$ G; t% m7 U- |3 q% w3 R" q( ?  R7 l4 |& I0 i: a1 O$ d$ _
{" ^- k2 N, Y) }: v0 \- K
* f: \8 P" k' a# y0 q
//调用socket函数返回的文件描述符
$ L' F1 }$ ]% m5 p6 t  I- [  T0 p
$ y, T/ H4 [4 r  k; E# }+ V) K. }; j* fint serverSocket;2 Q7 x* \* N- O) @6 }
. J$ I/ p( T$ N3 g& e: l# X- I9 e
//声明两个套接字sockaddr_in结构体变量,分别表示客户端和服务器9 D# ~. @/ |8 r6 y
1 P9 K( o# d0 {+ l( T/ C
struct sockaddr_in server_addr;
) }, d' c" v  }* A* o
3 ]( }4 X. v- ystruct sockaddr_in clientAddr;" `5 `; ~! r% W' Z. y. U, G$ t

# `# M0 B3 `0 P, Eint addr_len = sizeof(clientAddr);
4 R( \2 k: S1 t# o5 @
: N0 w( h8 \0 D. H! @* Vint client;# f. Q) b! K# N9 [; [, D
( J2 z* B2 K- Z. M! F
char buffer[200];
2 k( i1 w; q; m" s! w7 E& X& g- ~9 t/ z4 t# @( {
int iDataNum;
7 ]8 A) ]( r9 n# ~5 n7 b
9 M4 j' {  T- g& h  U9 d+ j. @//socket函数,失败返回-1
' M' L1 V8 L+ b, W! J. P' _3 F% }) f# f
//int socket(int domain, int type, int protocol);& z5 b$ E' e6 @4 Z  x
8 J: F+ j- F$ c
//第一个参数表示使用的地址类型,一般都是ipv4,AF_INET
- v& K6 z: n/ X8 @0 D' r$ \9 C+ i
//第二个参数表示套接字类型:tcp:面向连接的稳定数据传输SOCK_STREAM
, \  u' ~2 S; n* b
' Q) K/ J! _. T# ^1 ^//第三个参数设置为0: ^0 O- Z; K1 W0 A
, S: `$ h7 R# o: U( i1 Z
if((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ T7 h7 Z7 [$ S' M+ ]2 |3 n" h+ X+ T/ @# u% k: ~$ d0 A
{, G3 p5 m1 X  f2 f) {$ z
: H0 l. S) \4 V' h% h
perror("socket");) r: b7 u9 Z& @' O# @

; i" H: k* a9 o2 sreturn 1;
9 ~  X, ~. u8 G* o7 z5 J
: x- t- j# O: L4 D* W}! V( ^! O8 x8 p3 q& M; j/ D

: w* A# d) y. i: Pbzero(&server_addr, sizeof(server_addr));! O5 ~5 x6 B0 r8 D* \

+ V* _8 |: r! |. t( P  l3 i//初始化服务器端的套接字,并用htons和htonl将端口和地址转成网络字节序
7 R0 C* e" D, s7 k; G" ?, K8 E3 F5 z
server_addr.sin_family = AF_INET;' a/ T/ z3 N5 @% E+ `. E

- _7 ]* }; T  b* X* S3 ~server_addr.sin_port = htons(SERVER_PORT);, G( f  l1 |; l! z. e- _+ o

; |4 ]) U/ V0 g' I1 t5 G//ip可是是本服务器的ip,也可以用宏INADDR_ANY代替,代表0.0.0.0,表明所有地址! f2 _; \1 l3 M' T# ?' w
! M% o% u9 }. f: o9 }2 J  Z% `0 |
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);% }* @4 j4 |# S% Q+ s: C- n
- z3 |+ b; a; K7 M( T$ a) @8 I# y
//对于bind,accept之类的函数,里面套接字参数都是需要强制转换成(struct sockaddr *)
& @% ~7 b+ T8 N, ~2 _' }/ k  h7 E, u( k# k9 D7 X4 ^& n
//bind三个参数:服务器端的套接字的文件描述符," A% ^4 K" B9 Q0 ~

4 ~( l; f$ q8 z) y5 ^if(bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
" |: L9 y6 |" m8 d
, ~: h4 j+ S, u& d, l{1 K6 p  v: o9 s
; C. D/ t( R  A* ^, J5 g* @) g' w
perror("connect");2 E) ^+ f8 o5 x) U

7 _  l3 ?1 K! [6 g- Qreturn 1;
/ l" w5 J8 m2 g* z6 z" g3 S* c2 ?) `1 G  [2 |% L' [0 V
}
: v1 [0 T( r5 M: P- h, C6 `0 X% V" I5 O6 R
//设置服务器上的socket为监听状态
/ k; {7 Q9 }0 \3 F0 z" _; C2 |' r( g2 x8 Q2 E: G( u4 T
if(listen(serverSocket, 5) < 0); z( r# }2 e2 s9 ]+ V: m6 A
+ |8 G: n( g' s
{4 y  C! m) H, Y: X
* ^, ~# D3 z9 F) |0 ?' O
perror("listen");
, n- G* v1 d# v8 I# R' b. p$ D
1 R! _! Z! c' Preturn 1;
& u# g' D8 t) Z) Y& ?6 |, m8 u- j# d3 S9 @% R
}
5 q& v- n% G, }* J! h) b% S; T% s0 g
9 m; Y) U) `6 H2 U* }8 U3 b9 \while(1)
8 S( _0 M+ ^7 y% Q( j" a0 w( W  J3 m& r# Z; }: e6 M
{/ m3 x4 V" e7 l1 [
0 @6 u: K" s; i" c3 C
printf("监听端口: %d\n", SERVER_PORT);
8 _" u5 a: a/ l3 F. r4 s
1 t  w( x/ r& b. v6 F//调用accept函数后,会进入阻塞状态
! X4 X' j; z. G# Z1 y# b- ]; Q, O2 w6 L, T
//accept返回一个套接字的文件描述符,这样服务器端便有两个套接字的文件描述符,8 |" w) v1 }: G! f7 y" d; g

' y8 a  x: T4 m. S& H4 S. j//serverSocket和client。
( ?1 R  M  c  T6 e: k5 J( }, O- F9 F) X
//serverSocket仍然继续在监听状态,client则负责接收和发送数据
4 N* q  v& p! b7 x
( w' b% p  F6 ?$ {" o//clientAddr是一个传出参数,accept返回时,传出客户端的地址和端口号# v5 f! V  j9 K8 _# f$ ?6 q$ {
$ A" Z  P- `/ N% k0 ^) ^# F- @
//addr_len是一个传入-传出参数,传入的是调用者提供的缓冲区的clientAddr的长度,以避免缓冲区溢出。
8 H: X# z% k- @% W1 f0 Z; D& }  t' K+ y+ ]) q3 m6 \
//传出的是客户端地址结构体的实际长度。
9 p( \5 [' {& P; N0 Y! H) a, g
& F5 x8 V* x1 n7 Q- w* S  V; V//出错返回-1: h9 L7 T9 M) w! B$ S6 S2 q  w
" T9 N. e* r. L! K5 \! K
client = accept(serverSocket, (struct sockaddr*)&clientAddr, (socklen_t*)&addr_len);
/ R% [' E4 n( q. f- Z9 J5 s1 }. c6 P, V4 y* D1 O9 R5 Z4 q
if(client < 0)% G+ x* m9 f9 W  W/ M9 k
7 s) h) r' I0 g3 z& t+ ^% T* ?) f
{
) C# D4 o; M, C1 B: ]$ V7 B5 X0 P
perror("accept");! d8 t2 `3 W0 f( m1 e

% I2 O- |, j! ]* ?1 f: Zcontinue;
- O1 p, D8 v4 J; r- t
+ q# _+ u( x" ~7 }; G$ \. r}2 K. U* W! }3 C  o9 J
7 j7 z8 A# {% ^" e6 H
printf("等待消息...\n");
; G1 ^4 i9 P+ U8 B* A/ k. q
% G5 n: [( B% d//inet_ntoa ip地址转换函数,将网络字节序IP转换为点分十进制IP
- p& c+ P+ J- E0 I( [" z* O
. E' _+ d: o5 o; E! b3 k# u//表达式:char *inet_ntoa (struct in_addr);7 y/ O) e& Y  t# J

  O$ O. }% K6 _9 l) P  c5 H9 \, [5 f1 Wprintf("IP is %s\n", inet_ntoa(clientAddr.sin_addr));
8 f7 d6 s9 }7 y5 E7 ]
) j$ K" L3 c' yprintf("Port is %d\n", htons(clientAddr.sin_port));. s! c4 N3 t: q+ {

) l! m7 i0 b0 j2 O( u! e$ Zwhile(1): L4 N9 M# v4 q- i2 f: g; r
4 a+ k- t4 t$ I
{$ g) I& S& W1 ~

+ i6 W( @/ [& B/ h. z: h" Hprintf("读取消息:");# I  G1 m$ Z) S4 f

; s: q4 z' k* i" p# i+ qbuffer[0] = '\0';) q0 A: {" L- Y# g+ l
5 d$ A$ `9 l5 L) q# `* B$ h
iDataNum = recv(client, buffer, 1024, 0);
' e# ^0 r5 }/ V: a$ e" }0 _, A0 I& ^3 {6 H0 n
if(iDataNum < 0)
3 G( W6 g2 _4 @2 d0 g
3 X" Z& V7 k; v0 a2 H/ t{1 j9 f( A3 }' z( I) `8 t( A8 X

5 z- p) j1 n/ F2 wperror("recv null");
( A$ a; y. y; |7 {5 c8 y% e! Z/ N$ n) X; A
continue;( t5 V/ j8 l/ U$ s$ M2 l3 H! Y

2 v( i* S- @- z6 f7 W4 Z}) |' k( V5 |# J+ i6 V
* I6 M9 i+ S( H: j7 F" B( z: |
buffer[iDataNum] = '\0';0 y+ G/ \$ V6 P" D4 u$ I9 o
+ w  o1 s8 ]3 W+ t
if(strcmp(buffer, "quit") == 0)
) X# z. I* Z9 I' q; W" l, P9 j
5 C. e* K5 f7 [2 Z0 N) ~break;. }) [- p# N- u: Z& Z
7 b: P+ T$ q$ A5 g" C6 T9 Z9 I
printf("%s\n", buffer);) g$ ?0 w+ N8 |8 N; j: x

4 e# ]4 o* i6 G0 ^: ^9 ~8 [& K7 K4 A3 R$ H  |, I$ Y. n

+ ?5 e/ ^" m% |# G( R4 oprintf("发送消息:");+ `: o8 ~3 e1 n* D2 X# q" P" i

* L) k2 p7 I$ f; |9 xscanf("%s", buffer);; z- u3 f5 r/ ?: z8 D  G

$ s3 L  s2 Q' v0 ^2 vprintf("\n");2 _) \2 B3 q" }4 B

0 N# V$ P8 r- d& t2 [9 Wsend(client, buffer, strlen(buffer), 0);0 d- g) y- ^' B5 m' E/ F7 G

$ P2 t/ o: Y# M* _4 h1 O) _( Yif(strcmp(buffer, "quit") == 0)) i: J9 L% m9 f/ }+ ^6 m

7 I5 Z& F. h, ?: V5 Bbreak;
# m% M+ F% G5 ~# O7 S, f  G
$ w/ Q4 n! v# V  b4 X# [8 q  N}
0 N" `/ Y2 @4 |$ j1 f1 I" @3 C+ r' b9 P9 S+ X2 s5 t$ P( J3 |8 Z
}
( a+ s& P7 Y% y% y  |& o1 B: _0 L3 @( N( w
close(serverSocket);
! [! h7 r7 O4 u6 e) Q3 N& }8 y  j; b8 U
return 0;) h7 s) e/ X5 `$ m! H

0 V5 X7 @3 b- W! r. z4 O% ^  y}4 f& Y4 `; I% z  X
client.c
9 _: e+ l' G" e; x2 \+ ^6 A( P#include <sys/stat.h>
" f" ~& u. F. ]; a$ z& q+ I( s+ [: ]/ j/ @
#include <fcntl.h>$ |* T$ Z6 j0 d/ q! Y8 U; l

; _2 @( |$ s0 R( t% A- t#include <errno.h>
- V5 s5 o7 m' A+ ]; v* `6 q* B2 I& H- _) ^
#include <netdb.h>
. Z' {  r% V' Y2 Z# m4 P* x  c& I
#include <sys/types.h>7 ~6 l9 F. x3 |3 _
4 Y  J5 j% q$ k1 b- D. w1 M
#include <sys/socket.h>
: @5 S: Y) `" }# ^! w6 H, G* O7 s. P/ k
#include <netinet/in.h>
% D( ^  _( z. ~3 {7 C- V
) Q) N) C: @2 \! b#include <arpa/inet.h>
) n7 \( u7 \8 o8 j
* @: h8 Z9 b/ a#include <stdio.h>, o' d* R8 B2 T& j, _! j/ A0 V

( c3 d. Z# E# r2 P7 g0 t" d" f#include <string.h>
& `. h8 p8 ?) r( S0 s- ^- Y! M
7 E: C( k  f: S# H  g; h2 z% d+ P) ~#include <stdlib.h>
' Z: R6 O. R( g4 e& y# j9 d
/ ]1 G% T5 D  c3 a% E; G# N#include <unistd.h>- m9 U7 v# k* r8 J: e0 C5 T

+ h# h6 f7 k9 d# G#define SERVER_PORT 6666  c) G. D6 H$ w% N5 h6 D( Z

# b/ K: `2 K1 o* I+ X$ d: i  ^3 Y8 T& f# c/*
) h# c5 F4 \) o9 n连接到服务器后,会不停循环,等待输入,& T' p2 t3 e3 I7 G- i
输入quit后,断开与服务器的连接
2 k$ o! Q5 Z5 d8 E*/" h5 v: u9 P" N' R" [* E! |; C
; O# K) T7 X! ], j0 ]: O( y
int main()$ h% {* @9 P  l% @7 A6 z
& @. g2 P/ R8 C6 u5 v9 N& }
{- V+ y5 m: u$ M! R
1 _8 s: X* r& j, k) A) B
//客户端只需要一个套接字文件描述符,用于和服务器通信, D# b/ y1 N- P% |( s7 d% o8 z
) O& [5 U* w& M2 I% O
int clientSocket;- _- }3 }1 \" ?* ?8 i3 l6 U

  S4 ?( |7 g, s. z//描述服务器的socket: {4 }8 R3 o1 X# ]+ a

# j( h0 D# r6 }# astruct sockaddr_in serverAddr;
" e5 {7 o5 N# `. q' I8 h/ T  f" }7 H$ z# D0 d& N
char sendbuf[200];+ d  J1 D1 ^- i: U: j6 v- a  O2 O

* y) e( [; q/ x9 u9 Z9 z  [, V8 wchar recvbuf[200];. _; o% `" u; y; K9 w

! `3 k1 T4 F/ v9 J3 ?int iDataNum;6 Y- c9 o+ D8 r0 e6 b/ ~0 Q  q

' O0 O7 H& Y- s* c+ lif((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- z- p& r0 l, y. H0 t: q2 L, G$ R4 C/ U# R0 G4 f
{4 }# S4 o: @7 s
3 m6 K; w- z3 K# T1 i9 W. [
perror("socket");/ W) R+ f3 n6 ]6 k, C0 _# }* z& T

% R# ^" k" w$ N8 Q) w4 F& y0 L. H* nreturn 1;
+ s7 K  {5 E. j9 h$ ]! {7 {* W& s  ^2 R4 [: d# ?$ I' k
}
3 w+ H2 S0 C" l
7 b- C6 u7 |. W2 HserverAddr.sin_family = AF_INET;
! O2 j  P. p. z! r! n
4 Z1 L5 L+ `' `$ \% l) oserverAddr.sin_port = htons(SERVER_PORT);$ S* B4 d- G7 {* `
6 U7 F) c6 K* l, z  J# |4 ~
//指定服务器端的ip,本地测试:127.0.0.1
8 p9 b" \7 w7 p, I, r
5 N5 M1 O, ^% N& ?/ r//inet_addr()函数,将点分十进制IP转换成网络字节序IP
! M, ]  j; g7 g8 R8 ~0 o
' I# x" C2 u8 D  GserverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");( ]5 x1 ]/ Q3 J( l

$ y5 a+ c$ V& Z$ A3 w0 Lif(connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)( V# U  ?$ C( a* Z" p+ K. v2 l
+ A  _' B3 F) ?0 v
{0 J. E- s3 S& O+ N
3 W! X& E; j; u# e
perror("connect");
$ v6 ~( ^3 o/ A8 u0 i& D( u* [9 n4 n* O5 ^# }" h# t. g
return 1;- r: h8 l; W: K2 ~

: v' c( m8 l5 g& @3 _6 H; E}$ K/ n2 e; N, K% L

% m3 G. R3 K. Vprintf("连接到主机...\n");, h7 s' \; u& C( _5 n" t, V6 B

- f! ]( O! i9 e7 G! j1 p1 r6 Twhile(1)9 |8 c. |( m; x" S& ~$ f

/ e9 e" P3 [2 P4 G- ^{* K* l: E. v* I: o
7 _, b2 [: }4 O; C# Q# U
printf("发送消息:");* h+ e) x( D- G' R& m9 G

( M+ `. z) c: k) iscanf("%s", sendbuf);
1 d0 j+ H! ]8 q4 _8 a- ?% d
% p7 Y2 V" x. z! a1 y0 k' s9 Uprintf("\n");
( q7 {& A. e. N4 _$ G' O. v% n
7 c$ n& T- q/ q  r% D1 h5 `send(clientSocket, sendbuf, strlen(sendbuf), 0);* C- O; r9 A6 L$ g7 q9 U

  @" T: I1 |) K0 D$ ]$ l( x
/ {2 s6 {4 d8 J( k; S2 R3 k; k+ P! W( a; T; b8 A% y8 v' r
if(strcmp(sendbuf, "quit") == 0)! J- z! g( P7 e+ E/ U4 w+ R" d
3 |' N% Y4 S# ]0 N8 |) Z  c
break;
, N0 u: u! t8 M- ]# j0 B
; G4 q7 `) z. Y5 |  Gprintf("读取消息:");9 C  T8 n( M- Z" y" A$ M5 q
- o! X2 ^, b, M/ o; S
recvbuf[0] = '\0';
6 o1 ^$ H. R$ j+ X  [! r, X1 a6 t' k1 b- \5 R
iDataNum = recv(clientSocket, recvbuf, 200, 0);
9 e! [9 x$ r: U9 C
# D; M- b; i5 h. crecvbuf[iDataNum] = '\0';* m3 B$ K8 w  W) k
7 c2 P( Y- ~, m/ Z0 Y9 o
printf("%s\n", recvbuf);4 ^7 i' Y" g1 \* m2 }4 T+ @
, X; |7 Q- ~- b
}; j' U' m& h# D- c; F

! `1 b5 O# c- t; Z/ c8 g& n9 ]close(clientSocket);7 d- ^4 C8 f; U3 o9 B# }' A- F

9 J% P$ v" O' W2 b8 ]( yreturn 0;1 h1 J$ T3 V3 x$ G; T6 }( N# [

1 n5 w* G+ }( P, w# a}
" d# @, ^! d. S3 g$ q" |6 }' \" ~5 b5 V0 E1 `8 C9 P4 r
您需要登录后才可以回帖 登录 | 开始注册

本版积分规则

关闭

站长推荐上一条 /4 下一条

北京云银创陇科技有限公司以云计算运维,代码开发

QQ|返回首页|Archiver|小黑屋|易陆发现技术论坛 ( 蜀ICP备2026014127号-1 )点击这里给我发消息

GMT+8, 2026-4-8 21:36 , Processed in 0.052056 second(s), 22 queries .

Powered by Discuz! X3.4 Licensed

© 2012-2025 Discuz! Team.

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