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

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

[复制链接]

1

主题

0

回帖

12

积分

管理员

积分
12
QQ
发表于 2023-6-26 15:34:11 | 显示全部楼层 |阅读模式
C语言实现TCP-IP协议服务器与客户端互相发送数据的socket编程/ [! J3 G/ G/ t

$ v/ F% {! B$ W/ [" T- Plinux下用C语言实现TCP/IP服务器与客户端互相发送数据的socket编程- q1 n) Y8 k9 b5 H) p" F  A7 r
: b1 G3 O! |" A* x; M1 w/ U  u8 b8 H1 ?
server.c  K' z+ x' v2 ]) [( S0 t* j
#include <sys/stat.h>
" Y3 J- C9 f  z, ]
7 i" q- b9 ~; g8 l" @#include <fcntl.h>/ z) k% P9 }; U- w8 q2 h% p2 w

( F6 \* f5 Q# n#include <errno.h>
8 N7 @+ D5 v  t+ I9 Q
3 J# U7 s) l+ y; B0 }% O' ?" e5 ?#include <netdb.h>1 E' ]: O. c: {1 c  [
7 M, [, S5 X  E6 I# S
#include <sys/types.h>
! J  V6 _! t( ~- u3 Q; H
: ?/ m; q% F9 {4 y* U#include <sys/socket.h>
! N* x) b4 h! i" Z' ]
! X! k3 E2 d1 G$ h#include <netinet/in.h>
: ~9 w3 M  t" F) M' K8 v# z. S
% b$ l+ ?1 z" u#include <arpa/inet.h>- b% s" s# C7 w; ^7 n2 A% a7 N
& ]/ V6 }4 Q0 C! m, a- e! J
#include <stdio.h>
  {3 E% M- K" u' T
9 e( B2 {- T' A& [: l% P#include <string.h>
5 }8 t% S$ Q' b9 H- ?4 ?
8 v* z7 @3 T0 b5 f) i% ?7 m7 q# n#include <stdlib.h>, D6 O! |. ~6 [. }$ w

1 j) T$ w7 L( K; a#include <unistd.h>" P+ {0 ]; T8 k# ?9 b- c

. i6 _( ?1 V; H, p! d#define SERVER_PORT 6666! D% u& Z+ g/ z. M4 E  T7 V
' P6 V9 G  g+ G: }1 o8 l3 p. `
/*+ r5 D) D( x7 L* a& |5 G" c
监听后,一直处于accept阻塞状态,0 B- Y3 l3 L0 |' G
直到有客户端连接,8 _9 P  X7 z" F  K! N. ]/ |8 _/ U
当客户端如数quit后,断开与客户端的连接
5 Y/ v8 g; r% [7 g  ?# Q*/
+ k% J; o! S! T4 A# u2 r$ {1 A8 D$ ^. Z/ ]0 X/ o
int main()4 t7 u9 F* k$ O3 V
, d4 y: O$ Z2 s3 Y' k9 E
{
8 P2 F7 K4 f" a" c3 o; k; c
/ W# J6 J) T- h1 d//调用socket函数返回的文件描述符% ^& s  A/ S6 D$ o. d
% g  l. Z5 ^" ]8 H$ i" ^
int serverSocket;
4 k! K2 T. d& T: _+ M* f/ |9 z) P( `: [" {7 m2 [
//声明两个套接字sockaddr_in结构体变量,分别表示客户端和服务器; p9 j1 I- Y1 ]# s# i5 X
5 D* z: V4 f' b
struct sockaddr_in server_addr;# A6 m1 |% v$ ~' J) m6 Y- |3 u

  j- F% o/ K; J& n) s, H! y5 |struct sockaddr_in clientAddr;
; [) y( f* j4 g# c5 x4 E! c
7 m, t! W4 m! Vint addr_len = sizeof(clientAddr);
9 Z7 y9 {  P2 D) v/ L5 W) a
; r& _; ~% M+ V6 L, qint client;
4 a( d& F- f3 @  D7 U4 Y! J3 T
' o# U9 b8 [3 O' o  h$ dchar buffer[200];2 B- @9 _+ S: C9 j, [) h
+ d" C$ }& e5 w* \/ x
int iDataNum;% e; {( h; J5 F% S
# p, _+ f9 R9 w3 `* t6 u( t
//socket函数,失败返回-1+ j/ G4 k2 M/ Y0 h+ b/ r: o

. w2 j7 V% {2 l, [  L4 v7 v) J//int socket(int domain, int type, int protocol);
  M9 X, r3 K% T* U' n  n9 w; l( `* ]
1 H" s" @- N$ z+ W- o$ U1 L* T, n//第一个参数表示使用的地址类型,一般都是ipv4,AF_INET
7 e: ^% z! l; n( p% B3 `7 ]. C) s5 g% D# o4 u
//第二个参数表示套接字类型:tcp:面向连接的稳定数据传输SOCK_STREAM- b+ o5 F4 M" P& [
4 D2 G5 \: H0 {1 z1 i
//第三个参数设置为0
+ k( F% Y8 {: }* E( u
: S. {+ z( W+ Y) bif((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
! ]# ~/ v1 A6 t8 r$ R7 ?% W3 |* i8 d
{
9 s7 c* ]4 q& g; }5 m, O: ]: z8 n4 ]. o2 C) h5 a5 A
perror("socket");
- D( }/ o! T( O1 Z2 w1 F$ `7 N, v# P% a7 `
return 1;
. S+ }$ ?5 C2 i* Y; i. c8 s: P3 s) s, B
}
" K- b( J  r4 i; v( B! r3 N- z7 h7 _  M: K
bzero(&server_addr, sizeof(server_addr));8 P3 k8 U& b4 o4 g' X9 e

& H5 n, F, T3 Q, H, M//初始化服务器端的套接字,并用htons和htonl将端口和地址转成网络字节序
$ {( A0 G, J* W+ o+ B$ y( {
, }! J4 r( F; |+ Y; yserver_addr.sin_family = AF_INET;
& k" O2 g) N5 y: Q/ ]/ p) V1 u* n9 @4 N: ~
server_addr.sin_port = htons(SERVER_PORT);  i' ]* F5 N: z
; B& N7 h) K2 f7 \9 x& v# ~
//ip可是是本服务器的ip,也可以用宏INADDR_ANY代替,代表0.0.0.0,表明所有地址) O2 |& b* s4 T
. T7 C* k1 q9 W' o, X* r
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);" t9 [6 N# \( q6 w1 D/ q# G2 V

- N/ x) Z7 J" `6 z% X//对于bind,accept之类的函数,里面套接字参数都是需要强制转换成(struct sockaddr *)) |" e$ H  Q2 F4 j
# v. C. O! [" k1 Y
//bind三个参数:服务器端的套接字的文件描述符,
& d3 [1 \1 k. {  l- I7 @8 s5 u  W
if(bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)5 U. w, I6 D- p) }% }4 Q

9 a: P, w0 L2 O) S$ Z8 `3 w! D{
$ N/ R1 i/ |1 o" @4 L3 j) G% \" d% ?# z) {$ B: ^% i1 q
perror("connect");- V0 w% `2 f2 k$ I' ~& Q
  z+ b8 h$ f0 o; N' f; z9 e
return 1;
1 e+ m) K$ c* t+ i) ]9 i. q/ M
1 `* ?3 t% O, d9 k1 V  D}. p) i8 I2 W, Z0 J+ T
$ j1 D5 k2 k* \9 _- k7 Q( \
//设置服务器上的socket为监听状态
4 u$ k/ o* O5 n$ f
+ J" a  E5 \3 ~1 {/ W4 b" R4 Y1 |if(listen(serverSocket, 5) < 0): ?* T1 H9 H; N# }" Q. k  L0 [

& V6 I  f  k! l- x8 n) B{
9 }: S, O3 y, @5 t; e' D0 R  e, S( |1 f+ |% v3 t
perror("listen");
1 d3 r. v" ]7 s, D$ W1 a* I, ~: Z: ^$ ?3 |
return 1;
$ [9 L" C/ i# y3 O
9 x% _( h6 P( D- n- @}& Z: w& U; ~: F( |. e: g, {

- t! k- Y$ ~  l5 w% |- I0 owhile(1)- b3 \+ k. {3 |
7 E4 e' C; x6 h0 y8 G( J: i" ^& o
{
$ l% {  H/ U$ {0 `+ |5 B, ~* G! T
3 s' _4 N- L  e6 h& h+ h, Eprintf("监听端口: %d\n", SERVER_PORT);$ Z( ?# F0 V: j8 @2 F

1 y8 A( z1 A8 ^6 D% m//调用accept函数后,会进入阻塞状态
9 U. H! s! v9 }" K. R; ~8 a7 r1 N7 U" c2 n% e! p
//accept返回一个套接字的文件描述符,这样服务器端便有两个套接字的文件描述符,
( }4 Q" ?/ H9 F' O9 T, n; V) H  T
//serverSocket和client。! K  E" b! ?  f. B
1 a9 C& Y% \- G; ]" m
//serverSocket仍然继续在监听状态,client则负责接收和发送数据  Z/ z" \" Y) z# p% k  P/ v$ t
, y2 Y$ p  Q' i. S
//clientAddr是一个传出参数,accept返回时,传出客户端的地址和端口号/ ]! _) w+ u, ?' r7 C& I3 q
) N* U% F; Z+ `; I2 u  _% }
//addr_len是一个传入-传出参数,传入的是调用者提供的缓冲区的clientAddr的长度,以避免缓冲区溢出。# e' ~/ t1 H; P0 O; k" v
' y, h. G: o7 _4 `+ Y8 B. ^' e( Z- x3 r
//传出的是客户端地址结构体的实际长度。
/ y' T' U3 r, R9 q* I0 H4 K1 `# _
//出错返回-1% u7 k' y3 f/ X0 z1 x
5 Q3 j- w6 p- V+ S
client = accept(serverSocket, (struct sockaddr*)&clientAddr, (socklen_t*)&addr_len);
* Q' p) m4 l% m1 p+ V
4 j) T; u( C. P' s  t8 N' Pif(client < 0). Q0 i6 V& t0 N7 O  e( F

7 J3 Y* R" |- |{
$ `8 _! W/ P" o& ?: o& w3 d2 y' ~, ^; t
perror("accept");
/ o% P& d& }' N9 P9 z. h% I' T5 ]
) A- n1 S3 s, `continue;" M* c8 b: s$ \; I; Y2 l# B

, e9 h7 ~3 W1 S1 E( Z. B# }  n}
. r% s) O. J% ~3 s3 x; F0 _& v& }9 b) ]6 E' v# l  R
printf("等待消息...\n");
# ~# s3 @" m+ d* g
# n4 D# n6 R4 W  M3 c0 ]//inet_ntoa ip地址转换函数,将网络字节序IP转换为点分十进制IP
1 u- g! r1 G/ O) U" D5 o) P2 f
# W5 M$ @2 Z5 R) V) Q0 K. W! d//表达式:char *inet_ntoa (struct in_addr);/ Q' P3 Y+ w( Z8 S  s
. C: v0 `8 |9 H! j0 l
printf("IP is %s\n", inet_ntoa(clientAddr.sin_addr));+ B; b; i: a$ _( v* \
: }' Q* F$ ~; x% w" ~
printf("Port is %d\n", htons(clientAddr.sin_port));
% c& v, e' X0 N+ P& U7 M1 X6 I1 U' n/ r6 Y, i' k9 n! u- m" g
while(1)
6 f' t+ ~! |& I. j
& T7 w! p. d( I- I  P2 E/ k3 s! u{2 ^7 a% F% r: t/ K' T
6 s/ u) s: ^& K% F) I$ ~1 [
printf("读取消息:");. l- m3 f3 z5 \- \% U
! Z/ ^& q# o+ p5 I5 a. o) z% z+ B
buffer[0] = '\0';5 g$ M3 r5 g$ S, Q6 r
/ \2 K7 c3 l5 ]( c: x; P
iDataNum = recv(client, buffer, 1024, 0);2 r) f# i1 L0 Q5 r6 j' x1 j3 X
" E$ T' |2 x2 l6 W, m! \$ e& |7 P
if(iDataNum < 0)3 Z! D6 U# n1 d* T
1 L# J- q; m' R- l
{
/ ]" W; H8 c9 {5 C6 f! ~4 A
. M9 Z$ N0 o( O$ yperror("recv null");) {& `& a! K" ]' E3 w$ d; d  v$ N
' C! |  Z. ^- Q* f- g, @) A6 i
continue;, ^# ^( Z3 Z2 {( X- i( K

* d. y6 L( P. j' ^' N9 U# g2 C}
, g# z6 M! ?8 O8 X9 c+ o( W+ D  v$ c3 X- j
buffer[iDataNum] = '\0';
1 j' l1 C7 ^+ S4 `. w. Q9 q: B4 E' w9 n4 H7 m1 N4 @
if(strcmp(buffer, "quit") == 0)
0 E$ f* V; @) l
/ z  Y7 r+ l! `) x( X! H' A2 U% gbreak;8 L3 J+ @- J( N& j5 b- K

; N7 a5 z- `% t) W4 H9 d+ Yprintf("%s\n", buffer);
$ D/ Q3 ]0 ]& k, L% M
$ o' S8 ^) C% k: B( Q3 _8 q9 Y% m6 t& r/ u) n% l. h$ s

3 ]1 G3 R3 l; E/ a# wprintf("发送消息:");
4 V/ t, z; p2 _2 ?8 F1 u2 r
+ ?) t8 c0 J3 K: ^4 _scanf("%s", buffer);
  u' @# p2 H) ~% L8 S8 m1 i. H$ N- O  |3 y, t( f, S* J% x
printf("\n");
( L9 x/ O0 U8 W* z
3 H! Z$ A% e* U. Psend(client, buffer, strlen(buffer), 0);
4 r. t( {# o" u3 i2 x8 ~5 I5 C8 }! m3 C: I* X, P, c9 N/ z2 r/ w
if(strcmp(buffer, "quit") == 0)" l& O  A# f5 v9 w
# I& ^) A' ?& n. S
break;8 K( c, |0 @% [( u
+ {9 ]8 m' Y  w5 W) I& z
}6 Q3 o4 [; Y+ ~: Q0 o- E

1 X8 b8 ]7 ~0 X" ?4 ]) v/ s}% w" j. `' _! d, f1 P

+ m# N3 r% q2 g' X3 Bclose(serverSocket);& l+ f) \" b- M

( o/ c( @. D3 Creturn 0;
1 G" P; H, `* t. l; ^2 n1 b% D# g' f% A% H4 G
}: n# y5 H' B: a& K5 K
client.c1 h3 @/ I5 h, ]0 z' N& g9 U
#include <sys/stat.h>3 K4 w) c6 Y1 S; f5 r$ C

* i) [8 v% f. e" G& B#include <fcntl.h>
. k, m, Q0 E! a4 W4 Y% t! |+ P7 C; ]
#include <errno.h>
5 q8 J* I8 d5 z. O5 x. N! x
% }$ Z' ]1 ~7 D$ [. R" a2 N; B2 f#include <netdb.h>
& ?" C" ]2 P& Y8 z$ h5 N
% a, U! A# w$ @8 U  F( V#include <sys/types.h>
2 R" ?) O) w& }% G; y  V/ w  B
( l) _# F2 a/ v4 c#include <sys/socket.h>
* e' `) p! D6 _& r% M1 z& G2 `0 J& g  a3 {( q3 C
#include <netinet/in.h>
$ _* }! U  j  D: T5 E, D# x" w* c3 u- M1 B7 U$ \& o  G7 i
#include <arpa/inet.h>4 l3 x1 v8 O8 B& [
5 Q: A& h/ a1 T/ t2 e
#include <stdio.h>: Y! j& b, o$ Q6 \: r

: G! Y6 o: j$ H* j: u#include <string.h>
0 I* a, d4 h! V" ^! j. Q" s
: p2 D3 m( R3 p#include <stdlib.h>
4 n; A+ h& V* ^8 j8 |6 Y( P5 F7 {5 l8 B$ E" D, \/ c% M
#include <unistd.h>( ]) E' t0 s1 G
( H4 m" _% F( A3 r, c* U5 \2 s4 y
#define SERVER_PORT 6666
/ U3 v) T$ I+ `, s$ @1 ^
7 D+ a; x# n2 v5 q5 m/*
7 T# u* X7 _' n5 k, \/ ~2 m连接到服务器后,会不停循环,等待输入,
" s; r& c* }+ `) X: ]( F输入quit后,断开与服务器的连接
5 M+ _) A6 ^' ]& _* f1 U*/" K  k) _- R5 R1 t8 r3 o1 ?1 T5 u; L3 r

7 p8 R3 W! e' k: N2 g6 _int main()& C# R! [# P- a! ^/ U
; j4 v" r/ ^0 s0 [# ]2 r
{
* F3 i( J( K* U4 ]$ s2 J8 T+ ~4 i
+ ]2 U- E$ N$ M) T3 x//客户端只需要一个套接字文件描述符,用于和服务器通信6 J3 @- [0 \% ]5 l
& R, K$ c. W5 q! W' @% ~# W. S
int clientSocket;3 Q( }+ J# |$ _
+ @7 c& d- w0 T( T7 a' [8 K
//描述服务器的socket1 [; H2 j# ^+ c7 S4 }0 s( J) j# O

: z) w/ l0 C- F! l" q/ pstruct sockaddr_in serverAddr;' H8 C; B$ V/ w0 H" r

$ U" ]7 [$ b. r6 e- B5 J' E: Q/ _char sendbuf[200];' I# \9 N- V5 z3 F) P! |

6 Z3 E4 P5 i9 W" w- L0 vchar recvbuf[200];
7 e9 f3 m9 _  O7 O7 A' U4 d+ J& z; E$ W4 j( b
int iDataNum;
4 W8 G  m8 }, o! v& ~# F4 k+ Z: q7 A2 K4 C( I* V
if((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
0 y+ [2 r2 H) h" \# P) j
! ~2 ?/ T: X  i9 Z) b{0 [& N9 I0 h- O2 y( c/ ^0 ]( S# [
, u; I8 o; O$ |" G) U1 P1 g$ E7 Q1 }
perror("socket");0 Y2 y4 @, L1 S2 k9 A1 k

% l- \$ B, G" |4 B5 A6 Ureturn 1;
% P9 ^5 L- R8 J' ?8 D7 ]" ]5 N6 o- h4 ]% G& u! n# b
}
3 ^: R, j$ p; z
% s* [" z- l. l0 W, vserverAddr.sin_family = AF_INET;$ R+ `$ V7 G( W; o  x' w( t

0 T2 M: z' u( Q; X- g: dserverAddr.sin_port = htons(SERVER_PORT);
" S4 _8 o4 s- K# a: R6 ~% n! E. A% b* ]
//指定服务器端的ip,本地测试:127.0.0.1/ T. T- w% n9 s) a: G4 |
( |! |2 B7 A7 A) w
//inet_addr()函数,将点分十进制IP转换成网络字节序IP4 E; X3 [# t- v6 G; D
7 F( b0 r8 v- u. D/ ~
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");8 s& O" A8 [, @) C! Q/ e: K
( o0 R% u8 l/ @' H0 L5 d. y& y8 y
if(connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0); v/ B, M" d, Y- z7 l
6 B" d" s  V8 `( ~
{1 o* v6 P5 e) E$ i/ G, p  Q( L
* {3 U; H# }0 ]
perror("connect");1 ]' P; l$ m+ Y# @5 {! B. G! a" t

2 L; v- r; w, treturn 1;
; |3 k2 ?8 M. `9 B$ P% b9 J3 j
  E7 m+ E7 {4 G3 B% R0 w- v}& _  N- ?; z3 _# h2 s
5 V6 _1 ]) N4 Y2 d7 `. _
printf("连接到主机...\n");  z, ^6 \( d2 U! ]9 o5 Q

* T4 [: W' Z; X6 {& Twhile(1)! a% i: ]& c0 u
6 \( ]  }  I( T, g1 A8 l
{" u1 _0 v( n2 l4 I) v, U

6 j, p8 h6 G2 {) J% \* Yprintf("发送消息:");
8 \$ T' p# ~" W& j
7 L# F7 R( E9 w& kscanf("%s", sendbuf);  r5 d7 b2 a. B' Z

) ?$ E; e- w* Z" w2 ^) |3 D4 `. Wprintf("\n");
& s) j4 v- [2 I. n% n+ v) e% [5 q1 }! _$ [
send(clientSocket, sendbuf, strlen(sendbuf), 0);
3 q* e  }1 ^: S3 T/ H' J7 q, r
: @* f4 _9 y4 W* ]$ I3 c) ^+ x  f

( `$ n. z0 l7 T2 m, Bif(strcmp(sendbuf, "quit") == 0)
$ m1 a/ e% M* X. X4 v# Z7 B1 ]5 e2 j, }5 v$ e$ ^8 q
break;# c9 s( W0 k% N; B

" D% P7 F7 r0 V- W, r6 o% mprintf("读取消息:");
% _8 ]0 q- n% v4 E, _& R  l9 L6 |: j; @5 V4 J; h
recvbuf[0] = '\0';
' _2 I3 K* e9 e, i( _6 e9 ]1 L  ?; T
- ~, `, @, ~" [) wiDataNum = recv(clientSocket, recvbuf, 200, 0);) E1 |" ]8 ^5 L  R# e' b; p. H

; ~- B7 R, J  W" \1 O* ]recvbuf[iDataNum] = '\0';; I/ ], m5 [$ w

) N: C8 j4 A4 o9 a) h" Q7 Yprintf("%s\n", recvbuf);4 y) w9 A  K) F. ^& b7 K* ~

+ G5 |6 f$ Q1 V7 U8 R' u  \}
1 v9 i  r  E2 Y$ A( T0 m, a3 J" ^  p
close(clientSocket);( [  C% \0 q! \- Q: s0 P! v

- ?6 ~: y1 b; y. i, K0 ~+ Greturn 0;1 h( d, U( {& \& G, X

# l% Y- q, Q) t+ y1 r/ ?}6 E' ?! n1 z" b& k
( V) ], M8 X* a' E6 t1 \- O
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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