网络通信
客户端(Client)
客户端是指向服务器请求服务的计算机或程序。客户端通常是用户直接交互的设备或应用程序,它发送请求到服务器,并等待服务器返回响应。
特点 :
主动发起请求 :客户端主动向服务器发送请求,例如请求网页、数据或其他资源。
资源有限 :相对于服务器,客户端通常资源(如处理能力、存储空间)较有限。
例子 :
Web浏览器 :如Google Chrome、Mozilla Firefox等,通过HTTP向Web服务器请求网页。
Email客户端 :如Microsoft Outlook、Thunderbird,通过IMAP或SMTP协议与邮件服务器通信。
移动应用 :如微信、Twitter等,通过API与服务器进行数据交互。
服务端(Server)
服务端是指响应客户端请求的计算机或程序。服务器通常是提供某种服务的设备或应用程序,它接收客户端的请求,处理请求并返回响应。
特点 :
被动等待请求 :服务器被动地等待客户端的请求,并处理这些请求。
处理能力强 :通常具有强大的处理能力和大量的存储空间,能够处理大量并发请求。
提供服务 :服务器提供各种服务,如Web服务、文件服务、数据库服务等。
例子 :
Web服务器 :如Apache、Nginx,提供网页和其他Web资源。
数据库服务器 :如MySQL、PostgreSQL,处理数据库查询和事务。
文件服务器 :如FTP服务器,提供文件上传和下载服务。
客户端-服务器模型(Client-Server Model)
客户端-服务器模型是一种网络架构模型,在这种模型中,客户端和服务器各自承担特定的角色:
客户端 :发起请求,通常由终端用户使用。
服务器 :响应请求,提供资源或服务。
交互过程
客户端发起请求 :客户端向服务器发送请求,例如请求一个网页或查询某个数据库记录。
服务器接收请求 :服务器接收并处理客户端的请求。
服务器返回响应 :服务器将处理结果返回给客户端。
客户端接收响应 :客户端接收并处理服务器返回的响应,可能会显示给用户或进行进一步处理。
特性
UDP
TCP
协议类型
无连接(Datagram)
面向连接(Stream)
可靠性
不可靠,不保证到达、顺序、去重
可靠,保证顺序、无丢包、无重复
传输速度
快,开销小
稍慢,有握手确认、重传机制
数据格式
数据报(Datagram),一条一条
字节流(Stream),连续数据流
适用场景
视频直播、语音通话、游戏
网页浏览、文件传输、数据库访问
是否需要连接
❌ 无连接(直接发)
✅ 三次握手建立连接
是否分包/组包
应用层处理
TCP 内部处理(数据粘包/拆包)
UDP通信(无连接,快速传输)
UDP(User Datagram Protocol,用户数据报协议)是一种简单的、无连接的传输层协议。UDP通信中的服务器和客户端各自承担特定的角色,通过发送和接收数据报进行通信。
1. UDP 服务端
主要负责监听特定端口并处理客户端发送的数据报。由于UDP是无连接的,服务端不需要维护客户端连接状态。
工作流程
创建一个UDP套接字。
绑定到一个指定的IP地址和端口。
不断监听和接收来自客户端的数据报。
处理接收到的数据并可能发送响应数据报回客户端。
Python 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 import socket
def udp_server ():
# 创建UDP套接字 AF_INET: 使用 IPv4 地;SOCK_DGRAM: 数据报套接字(UDP)
server_socket = socket . socket ( socket . AF_INET , socket . SOCK_DGRAM )
# 定义服务器地址和端口
server_address = ( "0.0.0.0" , 12345 )
# 绑定套接字到地址和端口
server_socket . bind ( server_address )
print ( "Server is listening on {} : {} " . format ( * server_address ))
while True :
# 等待接收数据,最大4096字节,阻塞式,直到有数据到来才继续执行
# data是收到的数据)(bytes类型),client_address是客户端的IP和端口
data , client_address = server_socket . recvfrom ( 4096 )
print ( f "Received { data . decode () } from { client_address } " )
# 发送响应
if data . decode () . lower () == "exit" :
print ( "Server exiting..." )
break
response = "Hello, client!" . encode ()
# 使用sendto发送信息回客户端
server_socket . sendto ( response , client_address )
# 关闭套接字
server_socket . close ()
if __name__ == "__main__" :
udp_server ()
c++版本
C++ 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 //udp_server.cpp
#include <iostream>
#include <cstring> // memset, strcmp
#include <unistd.h> // close
#include <arpa/inet.h> // sockaddr_in, inet_ntoa
int main (){
// 1. 创建UDP套接字
int server_socket = socket ( AF_INET , SOCK_DGRAM , 0 );
if ( server_socket < 0 ){
perror ( "socket creation failed" );
return 1 ;
}
// 2. 设置服务端地址结构体
sockaddr_in server_addr ;
memset ( & server_addr , 0 , sizeof ( server_addr )); // 清空结构体
server_addr . sin_family = AF_INET ;
server_addr . sin_addr . s_addr = INADDR_ANY ; // 监听所有网卡
server_addr . sin_port = htons ( 12345 ); // 端口号
// 3. 绑定socket到地址和端口
if ( bind ( server_socket , ( sockaddr * ) & server_addr , sizeof ( server_addr )) < 0 ){
perror ( "bind failed" );
close ( server_socket );
return 1 ;
}
// 4. 接收并回复客户端
char buffert [ 4096 ];
sockaddr_in client_addr ;
socklen_t client_len = sizeof ( client_addr );
while ( true ){
memset ( buffer , 0 , sizeof ( buffer ));
int bytes_received = recvfrom ( server_socket , buffer , sizeof ( buffer ) -1 , 0 , ( sockaddr * ) & client_addr , & client_len );
if ( bytes_received < 0 ){
perror ( "revfrom failed" );
break ;
}
buffer [ bytes_received ] = '\0' ;
std :: string message ( buffer );
}
// 5. 关闭socket
close ( server_socket );
return 0 ;
}
2. UDP 客户端
UDP 客户端负责向服务器发送数据报,并处理服务器的响应。由于UDP是无连接的,客户端不需要建立和关闭连接,只需发送数据报即可。
UDP 客户端的工作流程
创建一个UDP套接字。
向服务器发送数据报。
接收来自服务器的响应数据报(如果有)。
处理接收到的数据。
Python 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 import socket
def udp_client ():
# 创建UDP套接字 AF_INET: 使用 IPv4 地;SOCK_DGRAM: 数据报套接字(UDP)
client_socket = socket . socket ( socket . AF_INET , socket . SOCK_DGRAM )
# 定义服务器地址和端口
server_address = ( "127.0.0.1" , 12345 )
try :
# 发送数据到服务器
message = "Hello, server!" . encode ()
client_socket . sendto ( message , server_address )
# 接收服务器的响应
data , server = client_socket . recvfrom ( 4096 )
print ( f "Received { data . decode () } from server" )
# 发送退出消息
exit_message = "exit" . encode ()
client_socket . sendto ( exit_message , server_address )
finally :
# 关闭套接字
client_socket . close ()
if __name__ == "__main__" :
udp_client ()
cpp版本
C++ 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 //udp_client.cpp
#include <iostream>
#include <cstring>
#include <unistd.h> // for memset
#include <arpa/inet.h> // for sockaddr_in, inet_pton
int main (){
// 1. 创建udp socket
int client_socket = socket ( AF_INET , SOCK_DGRAM , 0 );
if ( client_socket < 0 ){
perror ( "socket creation failed" );
return 1 ;
}
// 2. 设置服务端地址结构体
sockaddr_in server_addr ;
memset ( & server_addr , 0 , sizeof ( server_addr ));
server_addr . sin_family = AF_INET ;
server_addr . sin_port = htons ( 12345 );
// 将ip转换为网络地址格式
if ( inet_pton ( AF_INET , "127.0.0.1" , & server_addr . sin_addr ) <= 0 ){
std :: error << "Invalid server IP address" << std :: endl ;
close ( client_socket );
return 1 ;
}
// 3. 发送数据给服务器
std :: string message = "hello server!" ;
int sent = sendto ( client_socket , message . c_str (), message . size (), 0 , ( socketaddr * ) & server_addr , sizeof ( server_addr ));
if ( sent < 0 )
{
perror ( "sendto failed" );
close ( client_socket );
return 1 ;
}
// 4. 接收服务器响应
char buffer [ 4096 ];
memset ( buffer , 0 , sizeof ( buffer ));
socklen_t addr_len = sizeof ( server_addr );
int received = recvfrom ( client_socket , buffer , sizeof ( buffer ) -1 , 0 , ( sockaddr * ) & server_addr , & addr_len );
if ( received < 0 ){
perror ( "recvfrom failed" );
close ( client_socket );
return 1 ;
}
buffer [ received ] = '\0' ;
std :: cout << "Received from server: " << buffer << std :: endl ;
// 5. 发送exit 消息
std :: string exit_msg = "exit" ;
sendto ( client_socket , exit_msg . c_str (), exit_msg . size (), 0 , ( sockaddr * ) & server_addr , sizeof ( server_addr ));
// 6. 关闭socket
close ( client_socket );
return 0 ;
}
TCP通信
1. TCP服务端(监听,接受连接,双向通信)
Python 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 # tcp_server.py
import socket
def tcp_server ():
server_socket = socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
server_address = ( "0.0.0.0" , 12345 )
server_socket . bind ( server_address )
server_socket . listen ( 1 ) # 开始监听,最大连接数为1
print ( f "TCP Server is listening on { server_address } " )
conn , client_address = server_socket . accept ()
print ( f "Connected by { client_address } " )
try :
while True :
fata = conn . recv ( 1024 )
if not data :
print ( "Connection closed by client" )
break
print ( f "Received from client: { data . decode {} } " )
if data . decode () . lower () == "exit" :
print ( "Server exiting..." )
break
conn . sendall ( b "hello, tcp client!" )
finally :
conn . close ()
server_socket . close ()
if __name__ == "__main__" :
tcp_server ()
2. TCP 客户端(连接,发送,接收)
Python 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 # tcp_client.py
import socket
def tcp_client ():
client_socket = socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
server_address = ( "127.0.0.1" , 12345 )
client_socket . connect ( server_address )
try :
# 发送数据
message = "hello, server" . encode ()
client_socket . sendall ( message )
# 接收响应
data = client_socket . recv ( 1024 )
print ( f "received from server: { data . decode () } " )
# 发送退出消息
exit_message = "exit" . encode ()
client_socket . sendall ( exit_message )
finally :
client_socket . close ()
if __name__ == "__main__" :
tcp_client ()
操作行为
UDP
TCP
创建 Socket
SOCK_DGRAM
SOCK_STREAM
是否需要 bind()
服务器需要,客户端不必须
服务器需要,客户端用 connect()
发送方式
sendto(data, addr)
sendall(data)
接收方式
recvfrom()
recv()
连接建立方式
无连接
客户端 connect()
,服务端 accept()