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

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

[复制链接]

1

主题

0

回帖

12

积分

管理员

积分
12
QQ
发表于 2023-6-26 15:34:11 | 显示全部楼层 |阅读模式
C语言实现TCP-IP协议服务器与客户端互相发送数据的socket编程
' j) X! b  K1 Y& J7 Z  E6 ^
% Z/ ]! _+ w4 H3 u
linux下用C语言实现TCP/IP服务器与客户端互相发送数据的socket编程
8 C2 ~0 @! y2 k3 S* ^4 w# s. m' J$ ]/ @1 t  u4 p7 K
server.c
7 Y  I# {/ ~: m& K  s9 ~6 g#include <sys/stat.h>1 p  }' C8 ~9 ?$ @
2 V0 ]* Y+ ?8 c1 q) N3 S# |
#include <fcntl.h>
! Y: m0 r: Y( M2 w) Z/ ]4 X0 Y6 [6 s/ U# i) r* x# E
#include <errno.h>
/ i/ P( J' J# d! u& U" J0 Q  `+ P1 ?% ]
#include <netdb.h>( ~% D) r. Y6 \/ k

9 X+ I+ ^6 G5 }#include <sys/types.h>$ ]5 E. M9 F+ L! s& t6 d- @7 `( n. h
6 m; `! G' B% n) R, c. X
#include <sys/socket.h>" p( D' a8 c1 m$ d& J* e* `

. a" k, G  ^: c+ z6 y# P#include <netinet/in.h>
; E0 Q3 F$ t; T( y" {2 W# }) K: G
/ {" a+ ~, b' W2 C& q#include <arpa/inet.h>
) \$ [& i6 x* ]0 X2 y
$ L9 ^) ]6 b$ {; t* g6 K. C#include <stdio.h>
) F" p8 J' N; I: |" ^7 p! f% o+ j7 V" S5 U% O
#include <string.h>, R  a  u! l! i; L# O0 x3 r* b
7 V) G# L# `. G6 Z- z# ?( q6 {
#include <stdlib.h>
& f" o& {. [" ?' ]3 M. H# x3 w( T2 f" X7 v/ Y3 B9 M5 {
#include <unistd.h>
2 p! n+ |( F) v( h$ o9 F5 x# a* n! b+ d& q* A& P, v
#define SERVER_PORT 6666& g8 [% G' B2 W" D" l

2 b/ y. `' n, i8 I7 J/*
5 \% F+ f8 K( K7 P" _4 P5 V监听后,一直处于accept阻塞状态,1 o# C+ n/ P1 V* L
直到有客户端连接," r+ r9 v. n* ^) T. F, ]9 l
当客户端如数quit后,断开与客户端的连接9 V& p/ _6 }  a# ]# }5 D' x. [
*/9 y4 {" k, P1 g: H/ Q

. M* O$ N: d' S, D& Y6 C1 Bint main()# m9 s2 o5 p. ~

( Q9 Q5 [% P  R$ A$ q3 D) Y+ |{3 }  B2 p9 _4 a: O
( _) r/ T; J3 S- i% m# A( S% ^' J- d
//调用socket函数返回的文件描述符5 |2 P1 Y+ d" ^: A' |" A: f
" z. f% V2 r& N% H' t- L& a
int serverSocket;7 V9 n: {* X4 ~- P- E  F7 L1 e8 u9 U

* S7 t! E- C* D7 c# |  M0 D+ x- s//声明两个套接字sockaddr_in结构体变量,分别表示客户端和服务器
- Y5 V; G7 N0 C& Y0 C0 c( P' Y+ b% Y
struct sockaddr_in server_addr;; U/ x- }' W2 }5 E" `8 G

2 u5 [; W$ G, [- r' vstruct sockaddr_in clientAddr;6 f1 C/ n/ I* W' {" A& o3 G
  ?/ C# |: n1 P, ?" E
int addr_len = sizeof(clientAddr);
+ [9 h$ f5 C0 p# w: p$ \% n  `& V1 u/ l9 w/ U3 `
int client;
$ x3 j3 F& k0 i8 w7 d3 ?0 G& [+ _, o/ Q: ?& T: \+ {8 M% n0 L7 R8 V- }
char buffer[200];
1 [0 q% ]5 M% E! ?: L& D1 W8 K+ B( _# q
int iDataNum;* W+ ^! u, x# b( X- i3 X7 q7 t

4 ^+ j! v. l! }+ G8 ]# Z" Z//socket函数,失败返回-1
% o( Q$ A! k( o4 V- P! B0 e, C  _( p$ S5 M, S: f( I' L5 v# d
//int socket(int domain, int type, int protocol);
4 B1 Y% M% o9 Q! J2 D; e) g
& A! [1 z* M0 o0 F$ @& R3 R//第一个参数表示使用的地址类型,一般都是ipv4,AF_INET& J: k6 y% L. u7 Y8 Y/ q. |

4 q$ I' N% V. ~3 S3 J1 z8 w//第二个参数表示套接字类型:tcp:面向连接的稳定数据传输SOCK_STREAM
# k8 O' j5 m# Y4 M  b7 H+ l( |5 d4 Y; Y1 {. \; H- A
//第三个参数设置为0
; k, I, L' g2 B2 m  a4 s, ]  k! s/ r$ a# d9 c+ c
if((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
2 i( A: w1 J/ u7 F& g5 \# f) j7 ~% |7 y) K& S  s" A
{0 a  w6 n" [! C) z1 z$ }
$ U1 C' r0 z/ g3 _) L) c
perror("socket");
5 _2 K9 C$ x+ m( w* B
" }. [7 ~" D' k: Ireturn 1;, a2 k9 q! i' n$ i- |/ u9 o
1 a1 y" i8 h. w
}6 Y2 l- w' _. h" y6 G
+ ?# ?* v, W3 K6 q# F
bzero(&server_addr, sizeof(server_addr));5 b  R' G  R, {! q- N

! I& o& Z: h  h3 S) q7 I- ]//初始化服务器端的套接字,并用htons和htonl将端口和地址转成网络字节序
8 H2 R+ M. }/ Z5 W) L& r1 Z
- n. F0 S' o5 f/ ?  o& p( |) z4 x8 Gserver_addr.sin_family = AF_INET;# e. `9 p, D4 N9 f( s1 x
" C* i8 W% d; B# z) \/ N
server_addr.sin_port = htons(SERVER_PORT);
/ V$ B* G, K! B4 u* G! ~! U" u' U( P7 m
//ip可是是本服务器的ip,也可以用宏INADDR_ANY代替,代表0.0.0.0,表明所有地址
  M0 c6 }) x- Z5 G
0 G; n& t' f% f% Zserver_addr.sin_addr.s_addr = htonl(INADDR_ANY);' i6 W/ t2 L& M, B
- R5 I. T5 [! }. W
//对于bind,accept之类的函数,里面套接字参数都是需要强制转换成(struct sockaddr *)& N0 N: o/ `+ v, R6 D

( _: E7 B0 X5 s2 b; J5 H$ r//bind三个参数:服务器端的套接字的文件描述符,' H6 i" t& N4 y( P4 b

1 ^$ w8 s/ T! @) `  D- \0 dif(bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
0 i) m- a3 l2 |) K6 |$ j8 S* Q0 p# h* `
{4 q6 o8 T0 l5 E- r& C- s8 m0 s9 y
1 f2 u% X) ]9 p0 p$ k+ i
perror("connect");
% r, ?' X0 J: S7 k" P2 D% D7 s! X5 w$ g1 \' R& o( R+ a, P
return 1;
% Y5 I& ^# n: k1 |; `% L4 y
2 `" k7 C$ s8 D) \4 s$ ^, j& l2 v$ ?}
  m2 ~4 L# D- J1 ?
0 |, S, ^9 x# f% e//设置服务器上的socket为监听状态
, B* X$ R7 `# |6 F0 p8 P+ r# a7 {. A+ ^$ v, a, S5 n: M! U$ M8 T' E# @
if(listen(serverSocket, 5) < 0)7 Z7 N. u- ^; @  G

. K$ c4 G; P  ~6 ?4 G5 R6 K{* j: b5 \; A# @: D& b' H. K
$ M- w' L1 h6 L- c
perror("listen");
' I) a' i; E! o: X" r$ s! I1 E8 D* l8 v; N
return 1;
6 @3 s) Z  V9 |' p! w: z
  H$ |1 I$ E2 E+ f6 s}2 w4 a6 P8 n- T7 ~
& M( F1 b7 D1 {6 U, ?
while(1)/ a! Z  \2 {/ ~# z3 Q& w
% i# ]- ?; W5 g( r  O- D
{* z  }# }% A! f: E
# {, g+ {5 O! I' `
printf("监听端口: %d\n", SERVER_PORT);
# W9 M9 X  D2 i" x9 w* ?% a
' _5 g2 ~) }$ J, W6 @7 r; t//调用accept函数后,会进入阻塞状态
0 j! G- E2 c' o1 D% Z0 _9 r+ k1 f6 p9 `$ J2 ~9 |. ]3 n  J1 z
//accept返回一个套接字的文件描述符,这样服务器端便有两个套接字的文件描述符,
  D! A/ R6 d! H- P9 r# L# T) N5 j. C4 s. Y7 R
//serverSocket和client。$ d4 L  s& c  v  G1 Z

1 a+ R$ U! h7 a//serverSocket仍然继续在监听状态,client则负责接收和发送数据# [& M' W5 Q4 c8 ^% R6 I8 H
& z, A8 m7 ?4 n. R2 A4 {6 Z' m
//clientAddr是一个传出参数,accept返回时,传出客户端的地址和端口号
+ h" I, f! B7 E6 n- Y- L. W
6 b4 l* @  X$ p' z5 j9 w//addr_len是一个传入-传出参数,传入的是调用者提供的缓冲区的clientAddr的长度,以避免缓冲区溢出。& s8 l% n6 A1 y# O7 u
; F, i) @8 T2 n+ |( `
//传出的是客户端地址结构体的实际长度。* U% u8 z' P- p) r/ X4 P# p. f. @
2 _' n0 x  ]6 E: Z9 ]. G( i
//出错返回-1+ c" T3 s8 a- u+ Y+ O4 a/ ]

1 Q! I( V6 w/ \client = accept(serverSocket, (struct sockaddr*)&clientAddr, (socklen_t*)&addr_len);
2 d& J* _6 q9 X* n( _% @: k7 ?7 ?0 c4 R6 l
if(client < 0)
) X+ n5 k" ]9 X) o0 I! ^# H/ m3 D' Z' a
{% P: `7 S4 _" F" K5 p* P, @/ \
3 t5 s: |& X0 v
perror("accept");
( V; f: [1 G1 |+ a  `
% q& F; F& _5 w0 Dcontinue;) [" ~0 |/ y/ h( y2 Q( L9 P) n% e, I' ?
. ~, Z. c% v0 p  ~+ P. L% N
}
: E9 q7 _; l& z# [3 T$ k# P
0 ~. D/ w2 D6 q- K; R1 j3 n7 T: Uprintf("等待消息...\n");
. P% s% u4 R. u
! [8 s1 g$ y; Q) W//inet_ntoa ip地址转换函数,将网络字节序IP转换为点分十进制IP
8 @5 E7 C6 f- N. [8 w  J; ]8 }& I9 U2 l! H" V0 \6 v5 X# }& R
//表达式:char *inet_ntoa (struct in_addr);) L1 E( C& }1 F3 o$ b1 @4 |& U
8 O4 n, i  R$ Y$ d, ~+ N
printf("IP is %s\n", inet_ntoa(clientAddr.sin_addr));! ]# [* [5 R+ O, t: l3 t
0 [! b: X5 p8 E" X* U
printf("Port is %d\n", htons(clientAddr.sin_port));5 p: m9 W8 R0 {0 {5 C; G; V6 p

; h' r  Q; R, V' I5 b7 `while(1)2 c# r  w/ [) o7 d5 o" M8 B- c

& q5 E- G$ R  H# N6 M{
/ W  t* M. _0 O( T2 E, C/ n( g3 |* h! v- j9 Z
printf("读取消息:");
( J( Q' e. z& ]9 x7 a( |7 F" H; e' M! F% Q# X" }
buffer[0] = '\0';8 ]$ m1 B: @6 h) q
1 u; _' D, e: w# A5 h( l" U
iDataNum = recv(client, buffer, 1024, 0);  m0 W" x* e/ P! F  Q) v( ~
) y  _2 e) R5 {; b& ~/ a
if(iDataNum < 0)
4 \/ b+ X, _# O5 ^
4 M1 G$ X  \0 f! |* F# E9 l: a: G: N{7 m! L1 N$ e5 k) ~. E7 M( g

7 f, |7 P% V0 J. r& |9 [- ~perror("recv null");& v- q! w4 M; b

, n' Q5 }3 u5 g$ h% m& e7 _( H+ q& ncontinue;
' d$ V' y, @6 H5 P* D! l' W
: z  K( A% ^  @$ a+ |9 f}( h2 E, g$ H: \# ]

0 Z$ s3 r  \, s5 Q. \  Fbuffer[iDataNum] = '\0';
4 C5 a1 E7 r9 e* E- l2 F  Z1 J! y, r& L& }$ v- u
if(strcmp(buffer, "quit") == 0)
6 b8 }5 g7 x: U. Z4 s1 J8 x: K
, c" f9 n, A; O  _3 T+ j& {  E4 @- `break;% {  d! b2 n2 n' q

. k( L5 e+ d. [4 s5 gprintf("%s\n", buffer);
* Q3 F; t, b, ]2 b. Y$ A, x5 V, n) z8 f$ X# i
4 b: c9 I/ M" M5 c# o  U7 q8 ~
# U0 A* M. T6 v- D- z( y+ J
printf("发送消息:");  i' E/ U( `4 k! n. ^, Y; w8 N
7 R% [: k+ `" |) T9 R' T
scanf("%s", buffer);0 X0 [6 ~' z8 l) ]
9 l0 g% x3 ?. `4 \1 w1 X- I* V
printf("\n");5 X" V, j- {* M3 s- j7 r- }
% H" x5 m9 {! D4 Q0 s9 U
send(client, buffer, strlen(buffer), 0);
8 B% x- \* w) G  h, }
7 ^" s7 K# K: fif(strcmp(buffer, "quit") == 0)
2 o& e7 I0 x8 L( |" f6 F/ _  l9 S: R7 ?
break;
2 f7 j  o% U7 r3 n7 h& ^2 N2 e+ A
}9 U' O0 z5 d0 L1 y6 l
& s' y/ V, c2 ^# i+ g
}
4 u5 g( _5 E9 m* [8 B4 q" E  N
& }- G: Q* S4 w+ xclose(serverSocket);* A$ Z5 l* @' z* L0 P

5 Q3 I# d, f. K9 A  q- `return 0;
6 Z' x7 v' f& q; h. [  h, s
5 T9 H6 {4 a) P}
( ~. I' ^0 f  `# `8 Uclient.c
2 R: Y. I7 q1 o- a! A; Y#include <sys/stat.h>
3 ]* k, Z2 c% J$ \1 T. V9 Z3 Y2 A# ^/ {$ D
#include <fcntl.h>
$ v& Q  I- l. X8 q/ l
" S9 i7 M* Z4 g2 }7 w#include <errno.h>
1 F4 [9 [) q* G/ l, w
0 E: ~; |1 `3 h: d3 Z#include <netdb.h>
0 f1 N' {* v+ M6 N' N
2 \0 N! h  M' U+ A#include <sys/types.h>
' z; S- Y; \# V1 W, c6 l! |4 V0 {5 E2 p2 c, X7 Y# H. n
#include <sys/socket.h>0 i! h  |! r# X. y  v' M* |

9 {' _: B* N. ]# R#include <netinet/in.h>7 U5 q9 X9 E# }; X. M* q) A8 J, g( r

" b2 y5 q3 G8 m: c- c% S5 a#include <arpa/inet.h>$ l, \& x* \7 O% z' `. {
$ S% q5 {- T. [% e' l5 z, T
#include <stdio.h>$ E) l. ^, P% W9 z( n- v
; U8 T8 e' l  k, f" I. n1 I* M
#include <string.h>: L+ N0 O( O$ p' o5 }
4 G3 E! I/ j3 K. r! P  ]% U; p
#include <stdlib.h>
4 N0 y9 l1 r7 c" I9 \4 X3 u$ j6 Y& ]" M. d" G# b" w# \
#include <unistd.h>
1 F  l6 G: v& x4 v8 C1 _1 i' |
2 ~; t! X, t( J+ L0 b- t4 B! F( G0 m#define SERVER_PORT 6666/ z2 n  k, ~+ Y. e! F

7 m9 Z7 x0 `7 G' S+ d0 U/*
9 E* z. }" Y5 N6 k; b  v4 m连接到服务器后,会不停循环,等待输入,) F/ G+ r8 T8 g5 j- ~
输入quit后,断开与服务器的连接
" w; W: N3 ^2 W*/7 J9 T% b! \0 ]

% T) m5 A5 G! s; i5 wint main(). N* B; C3 b+ q0 X* [+ v& F& y# m
) f4 b! e' w( }( i' z; c: k% r
{
$ C/ U! w& c3 F  p' V) L4 I4 W' |, e7 p3 y
//客户端只需要一个套接字文件描述符,用于和服务器通信* Q3 H; {0 _7 {
/ S' t: w. u* Q
int clientSocket;6 ~7 f% e8 w+ D

7 R2 i8 }6 ]" \; H' W, o: w8 s//描述服务器的socket4 C$ S$ |5 A1 c1 X  s8 ^
4 T* e5 Y- i- B  e* e) O# h& ?
struct sockaddr_in serverAddr;
; @+ w1 e3 K: R+ U' b
* Y& i! d5 i* D& ?7 R- kchar sendbuf[200];2 Z1 G  d3 {- k" W* Q4 H( U4 x9 [$ M
4 T" C* U+ s& h" G7 n  A- C) T( D! ?- _
char recvbuf[200];
5 A* V6 p' W, r% D$ j* ]  L1 e3 u
9 ]/ @! o% }  e4 H$ Dint iDataNum;
# k9 R' c5 _% ?0 S, g* K& u
0 [/ H2 X5 }/ L+ V; `* U4 gif((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0). a" v7 V4 D  T) ?$ Z% {

& W6 P& r. a; R7 P  e" ^6 Y{
" n: k* a4 A1 B( Y- }8 f3 [3 ]9 i" M# A1 F+ R
perror("socket");6 M% j7 W/ U- d$ b0 J

: `$ |4 A9 s  }! p/ b$ \return 1;
# p! f5 D% j, M, L6 s8 p: @1 L: d' d0 H( R, ?/ E* z1 y4 H
}5 F$ i" I: X5 _0 |- X
3 i7 T. P. s# d* e# v3 w, _; F0 n
serverAddr.sin_family = AF_INET;3 n/ e+ C- P5 Y8 C- S2 q
# t( ?& A/ b5 M$ y9 m
serverAddr.sin_port = htons(SERVER_PORT);5 z- S- J. I3 t- Q0 z3 O" R

5 ]0 W7 U" ^+ U- _//指定服务器端的ip,本地测试:127.0.0.1+ s% Z$ B  n1 m2 J
. u) ~& R$ w  _8 n( v8 d
//inet_addr()函数,将点分十进制IP转换成网络字节序IP
2 w  y  W# \7 w$ T( r" c( b# q8 V: q3 v4 v4 l; `& v7 C
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
( a4 U* M% u( V( f0 U2 M, j+ O' e& N& _: ]4 e
if(connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
' [+ r6 A' f- ^
% G7 O- q) \0 R) w{  c' e: E" X6 M* E/ d7 U; K
% Y7 N; Z# m8 u
perror("connect");2 U" ~! Q4 H' l; U

) U( e# }. y8 |5 b% L6 T8 Jreturn 1;
6 ?# I# j3 I5 f: j0 O
; E0 |* M( M) X}
+ |6 e' u$ P% c" v0 b2 F! b) K9 ^! x; y( ~
printf("连接到主机...\n");* u- B$ k# [! @7 w
& Q& S/ Y- S6 d! I
while(1)- D. o0 S/ L% V9 n3 O/ d' B1 f. W

7 Z% X* c- |+ Y6 v- g/ S8 H1 R{  I! b! w' l# `/ z7 p. h: h1 q

$ x' {  |' l2 O5 M( ~. d3 |printf("发送消息:");" d& S9 i  s6 U) F2 w) c
# g9 Z- L/ m& |+ p
scanf("%s", sendbuf);( W: |" x9 z8 x: R$ D* L! D" R5 X8 Z1 {

  @' Z! H5 q% ~5 u, Wprintf("\n");. y: p3 v. ]* V" V# a9 w
! k7 Q, G9 `7 z2 f- P* p/ W
send(clientSocket, sendbuf, strlen(sendbuf), 0);
; y+ T3 Q( a+ S3 l4 C2 t/ Y& `
. B9 G8 r' d0 a# X% |) V( S7 J- d1 O) A8 [

6 X+ F- h' D- u. s! {% i6 _! _' f2 Qif(strcmp(sendbuf, "quit") == 0)
, M5 P+ b" H  B
3 P0 s( b& z( f# r" Jbreak;4 _6 I! l3 C3 m. d
5 o# U- i+ c. r6 n
printf("读取消息:");
8 U, v# j' m. i7 b8 k
% [' `5 ]# R: {7 ?- z) z. Hrecvbuf[0] = '\0';$ T/ ^  ^$ e9 `+ ^

: f9 I  k% F9 w; w$ ?9 UiDataNum = recv(clientSocket, recvbuf, 200, 0);
/ }3 S# ~0 J; w' @( F# c- V0 z; d# l( a# p7 X5 @8 R
recvbuf[iDataNum] = '\0';
% |+ U7 v; y# [4 `8 t- x1 f: P& ^) i" J& l: _; L* |
printf("%s\n", recvbuf);' U' p2 d/ r1 L: D/ w
% b. c. o, N% z
}
2 b# y4 F: o( l) J) H# r+ H( o
7 X+ t& l7 i& H( |# {6 eclose(clientSocket);
. T  z7 ]2 {! E, q9 k0 g# d: _; R* c1 f) M# j6 p: p( o
return 0;
. D0 `/ l/ D$ J7 Z5 P3 C, W- ~6 Q3 ~! L* O- j. _& _3 x# y: {9 n5 R* S
}' O7 Z- @. i) z# J* v; ?

* }' M6 `0 u! I3 I
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2026-6-12 01:06 , Processed in 0.135581 second(s), 22 queries .

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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