一、基本模型
每一个应用程序客户端要实现数据传输,都需要套接字去发送或者响应网络请求,客户端通过套接字,沿着网络设备将数据发送给其他客户端,相应客户端解析并接收数据。
1.1、层次划分
osi 模型 |
各层级说明 |
---|---|
应用层 | 供操作系统或应用进行网络通信的标准接口 |
表示层 | 将不同的编码方式转换成网络通信中采用的标准表现形式 |
会话层 | 不同PC不同进程间建立或解除连接,插入同步点 |
传输层 | 两个主机间端对端的数据连接与传输 |
网络层 | 选择路由并正确的找着目标主机 |
数据链路层 | 两个相邻节点间准确的数据传输 |
物理层 | 原始比特数据在物理介质上的传输 |
tcp/ip 模型 |
层次说明 | 网络协议 |
---|---|---|
应用层 | 供操作系统或应用进行网络通信的标准接口 将不同的编码方式转换成网络通信中采用的标准表现形式 不同PC不同进程间建立或解除连接,插入同步点 |
Telnet ,FTP ,SMTP ,DNS ,HTTP |
传输层 | 两个主机间端对端的数据连接与传输 | TCP ,UDP |
网络层 | 选择路由并正确的找着目标主机 | IP ,ARP ,RARP ,ICMP |
数据链路层 | 两个相邻节点间准确的数据传输 原始比特数据在物理介质上的传输 |
网络通信硬件及接口 |
OSI
(Open System Interconnect)开放系统互连参考模型七层协议模型,是一个理想化的网络互连参考模型,但基本不使用.
现使用的是TCP/IP
四层网络模型
TCP
和UDP
的区别是前者是可靠的的网络互联协议,而后者不可靠ARP
指的是根据IP
地址获取MAC
(网络设备的物理地址,硬件地址,每台电脑中均装有网卡,其地址为MAC
地址)RARP
为根据MAC
地址获取IP
地址
传输层次说明
- Python是在应用层的HTTP协议之上进行开发
- 网络编程,主要是了解Python能编写的最低的层次即传输层的基本情况
- HTTP协议是基于TCP之上的,因此需要了解TCP连接的基本过程
1.2 TCP
链接
建立连接(三次握手)、数据传输、断开连接(四次挥手)
1.2.1 建立连接
连接过程
- 首先由客户端发起同步请求(SYN),即想建立连接,服务端处于监听状态,可接收客户端的请求。
- 服务端收到同步请求,发送应答信号(
ACK
)给客户端。 - 客户端接收应答信号,已建立连接并发送已建立连接的应答信号给服务端,连接建立完毕。
1.2.2 数据传输
客户端发送数据传输请求,操作系统接受请求并接收数据,发送数据给相应客户端,客户端接收数据并发送响应信号,客户端接收。
1.2.3 断开连接
断开过程
- 客户端主动请求断开连接,发送结束信号(
FIN
),客户端等待关闭 - 服务端接收FIN信号,响应请求,发送
ACK
信号,第一阶段完成(客户端已无数据发送给服务端,但服务端可能还有数据发送给客户端, 故还有后续过程) - 服务端被动关闭,发送
FIN
信号,等待客户端确认 - 客户端发送
ACK
,等待服务端关闭,服务端接收信号,关闭连接,客户端关闭连接
二、IP
地址和端口
2.1 IP
地址
IP
协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。即为每一台计算机编号,以便于在网络中定位到一台计算机的位置。
一些特殊的IP
地址
127.0.0.1:本地回环地址。该地址指电脑本身,主要预留测试本机的
TCP/IP
协议是否正常。只要使用这个地址发送数据,则数据包不会出现在网络传输过程中。0.0.0.0:代表的是本机所有
ip
地址,不管你有多少个端口,多少个ip
。如果监听本机的0.0.0.0
上的端口,就等于监听机器上的所有ip
端口。换句话说,就是只要数据报目的地址是你机器上的一个ip
地址,那么就能被接受。
2.2 端口
- 端口用来唯一标识应用程序
- 每个应用程序都占了一个端口,一个端口同时只能被一个程序使用
- 共有65535个端口
- 数据传输,发送与接收必须通过端口,指明了数据应发送的进程编号。每个进程都有一个端口号,以此来作为数据传输的门户。
三、套接字
3.1 TCP
3.1.1 服务端
socket常用的方法 | 描述 |
---|---|
socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
创建tcp 服务端socket对象 |
socket对象.bind((ip,port)) |
绑定ip 和端口 |
socket对象.listen() |
监听客户端发起的连接请求 |
socket对象.accept() |
接受客户端连接请求,返回用于与客户端通信的对等socket对象,和客户端的ip 和端口 |
对等socket对象.recv(int) |
接受客户端发来的消息 |
对等socket对象.send(data) |
向客户端发送消息 |
socket对象.close() |
关闭连接 |
对等socket对象.getpeername() |
获取客户端的ip地址和端口 |
示例代码
import socket
# 创建ipv4的TCP socket
server_tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定ip和端口
server_tcp_socket.bind(('127.0.0.1', 8080))
# 监听客户端链接
server_tcp_socket.listen()
# 接受链接,返回一个用于和客户端通信的对等套接字和客户端ip地址和端口
clientSocket, address = server_tcp_socket.accept()
print(f"{address}已连接")
# 通信
## 接受客户端发来的消息
recv_date = clientSocket.recv(1024)
print(recv_date.decode())
# 将收到的信息返回个客户端
clientSocket.send(recv_date)
# 关闭
clientSocket.close() # 先关闭对等套接字
server_tcp_socket.close() # 关闭套接字
3.1.2 客户端
socket常用的方法 | 描述 |
---|---|
socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
创建tcp 客户端socket对象 |
socket对象.client((ip,port)) |
连接服务端 |
socket对象.send(data) |
向服务端发送数据 |
socket对象.recv(int) |
接受服务端返回的数据 |
socket对象.close() |
关闭连接 |
示例代码
import socket
# 创建客户端tcp_socket
kehu_tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务端
kehu_tcp_socket.connect(('127.0.0.1', 8080))
# 发送消息
kehu_tcp_socket.send('hello world'.encode())
# 接受服务端返回消息
recv_data = kehu_tcp_socket.recv(1024)
print(recv_data.decode())
3.2 UDP
3.2.1 服务端
socket常用的方法 | 描述 |
---|---|
socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
创建udp 服务端的socket对象 |
socket对象.bind((ip, port)) |
绑定ip 和端口 |
socket对象.recvfrom(int) |
接受客户端发来的消息,返回客户端发来的消息和客户端地址 |
socket对象.sendto(data, address) |
向客户端发送消息 |
socket对象.close() |
关闭连接 |
import socket
# 创建udp服务端的socket对象
server_udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定ip和端口
server_udp_socket.bind(('127.0.0.1', 8081))
print('等待用户来连解')
# 接受客户端传来的消息,返回消息和客户端的地址
data, address = server_udp_socket.recvfrom(1024)
print(data.decode(), address)
# 将客户发来的信息返回给客户端
server_udp_socket.sendto(data, address)
3.2.2 客户端
socket常用方法 | 描述 |
---|---|
socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
创建udp 客户端socket对象 |
socket对象.sendto(data, address) |
向服务端发送消息 |
socket对象.recv(int) |
接收服务端返回的消息 |
socket对象.close() |
关闭连接 |
import socket
# 创建udp客户端的socket对象
client_udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 向服务端发送消息
client_udp_socket.sendto('hello world'.encode(), ('127.0.0.1', 8081))
# 接受服务端返回的消息
recv_data = client_udp_socket.recv(1024)
print(recv_data.decode())
# 关闭客户端
client_udp_socket.close()