python网络编程基础
TCP/IP协议
计算机之前进行网络通信,首先需要双方确认通信所使用的协议,之后才能按照这种协议进行数据的传输。
tcp/ip协议的作用:
TCP/IP
是用于因特网(Internet
)的通信协议。它是对计算机必须遵守的规则的描述,只有遵守这些规则,计算机之间才能进行通信。IP - 网际协议
TCP - 传输控制协议
UDP - 用户数据报协议
协议 | 功能用处 | 端口号 | 对应模块模块 |
---|---|---|---|
| 网页访问 |
|
|
| 阅读和张贴新闻文章 |
|
|
| 文件传输 |
|
|
| 发送邮件 |
|
|
| 接收邮件 |
|
|
| 获取邮件 |
|
|
| 命令行 |
|
|
| 信息查找 |
|
|
TCP和UDP:
UDP 在传送数据之前不需要先建立连接,远程主机在收到 UDP 报文后,不需要给出任何确认。
适用于一些及时性的服务
TCP 提供面向连接的服务。在传送数据之前必须先建立连接,数据传送结束后要释放连接。
TCP 一般用于文件传输、发送和接收邮件、远程登录等场景。
三次握手:
复习一下字符的含义:
SYN
:连接请求/接收 报文段seq
:发送的第一个字节的序号ACK
:确认报文段ack
:确认号。希望收到的下一个数据的第一个字节的序号
客户端向服务器发送一个SYN报文请求。
服务器收到客户端的SYN报文后,返回一个SYN报文作为回应,并同时发出ack确认。
针对服务器返回的确认,客户端也发送ACK进行应答。
为什么要进行第三次握手呢? 通信就是数据的发送与接收,第三次主要目的就是双方确认都能够正常发送和接收。
四次挥手(四次握手):
建立一个TCP连接需要三次握手,而释放一个TCP连接需要四次挥手。 TCP的半关闭特征:提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力
复习一下符号:
FIN
:连接终止位seq
:发送的第一个字节的序号ACK
:确认报文段ack
:确认号。希望收到的下一个数据的第一个字节的序号
假设客户端先关闭连接:
客户端发送一个FIN报文,主动关闭TCP连接。客户端处于FIN_WAIT1状态,等待服务器的确认。
服务器收到FIN报文后,返回一个ACK确认报文。此时TCP处于半关闭状态,客户端到服务器的连接释放。
如果服务器想断开了,像客户端一样,发送一个FIN报文,等待客户端的回应。
客户端收到FIN之后,发送一个ACK报文应答。
套接字(Socket)
socker是计算机进程间通信的一种实现。不同主机甚至同台主机不同进程之间的通信。其包含进行网络通信必需的五种信息:连接使用的协议,本地主机的 IP 地址,本地进程的协议端口,对方主机的 IP 地址,对方进程的协议端口。 套接字:ip+端口。
其实Socket 就是在应用层和传输层之间的一个抽象层。
socket分类:
流格式套接字(SOCK_STREAM)
TCP通信协议,流式传输
面向连接的可靠的传输
顺序传输
建立虚链路
数据的发送和接收不同步
数据报格式套接字(SOCK_DGRAM)
UDP通信协议,数据报传输
无连接的不可靠的传输
不使用传输层协议,直接和底层进行数据传输,如IP
限制每次传输的数据大小
数据的发送和接收是同步的
socker通信过程:
对于网站,通信模型是服务器与客户端之间的通信。两边都创建一个socket对象,然后通过socket对象对数据进行传输。通常服务端处在一个循环的状态,等待客户端的连接。
在python中,网络编程主要用的就是socket模块。
#socket_family: 主要包含AF_INET、AF_INET6、AF_UNIX
#socket_type: 主要包含SOCK_STREAM、SOCK_DGRAM、SOCK_RAW
#protocol: 用于指定创建套接字的协议,通常默认省略值为0
socket(socket_family, socket_type, protocol=0)
# 创建TCP套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
服务端过程:
#server
import socket
# 创建 socket 对象
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定端口
s.bind(('localhost', 9999))
# 设置最大连接数,超过后排队
s.listen(5)
while True:
# 建立客户端连接
c, addr = s.accept()
print('收到连接:', addr)
# 发送数据
c.send('谢谢你的连接'.encode())
print(c.recv(1024).decode())
# 关闭连接
c.close()
调用accept()时,socket会进入waiting状态。客户端请求连接时,建立连接并返回服务器。accept()
返回一个含有两个元素的元组 (conn, addr)。第一个元素 conn 是新的 Socket 对象,服s务器必须通过它与客户端通信;第二个元素 addr 是客户端的 IP 地址及端口。
客户端过程:
#client
import socket
# 创建 socket 对象
s = socket.socket()
# 连接到服务器
s.connect(('localhost', 9999))
# 接收数据
s.send('我已经连接上你啦'.encode())
print (s.recv(1024).decode())
s.close()
客户端过程比较简单,创建一个socket对象,然后连接服务器,发送数据,读取数据。
Socket 模块的方法
服务器端套接字
套接字方法 | 解释说明 |
---|---|
| 将地址 |
| 开始监听 |
| 被动接受 |
客户端套接字
套接字方法 | 解释说明 |
---|---|
| 连接到 |
| 功能和 |
公共用途的套接字函数
套接字方法 | 解释说明 |
---|---|
| 接收 |
| 发送 |
| 完整发送 |
| 接收 |
| 发送 |
| 关闭套接字 |
| 返回套接字的远程地址,返回值通常是一个包含 |
| 返回套接字自己的地址,返回值通常是一个包含 |
| 设置给定套接字选项的值 |
| 返回套接字选项的值 |
| 设置套接字操作的超时时间; |
| 返回当前超时期的值,单位是秒,如果没有设置超时期,则返回 |
| 返回套接字的文件描述符 |
| 如果 |
| 创建一个与该套接字相关连的文件 |
TCP编程:
上面分析客户端和服务端通信的过程就是TCP的一个例子。
TCP
协议是面向连接的,会事先建立好连接,所以不需要指定地址
UDP编程:
UDP
是面向无连接的,所以每次发送都需要指定发送给谁
#server
import socket
# 创建和绑定套接字,不需要监听连接
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('127.0.0.1', 9999))
while True:
# 不需要接收连接,直接接收数据
data, addr = s.recvfrom(1024)
if data.decode() == 'exit':
exit()
print(f'连接的主机:{addr}.')
print(f'收到的消息:{data}.')
# 服务端给客户端发送数据
s.sendto(bytes(f'{data}', 'utf-8'), addr)
# 关闭服务器套接字
s.close()
#client
import socket
HOST = '127.0.0.1'
PORT = 9999
# 不需要使用connect方法连接到服务器
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
msg = input('输入要发送给服务器的数据: ')
s.sendto(bytes(msg, 'utf-8'), (HOST, PORT))#发送数据给服务器
data = s.recvfrom(1024)#接收服务器发来的数据
print(f'服务器发来的数据: {data}')
- 感谢你赐予我前进的力量