Day6 PythonWeb全栈课程课堂内容
1. TCP协议介绍
-
TCP协议,传输控制协议,是一种面向连接的,双方必须先建立连接才能进行数据的传输、电话接通才可以传输数据,比udp可靠。
-
TCP特点:面向连接,可靠传输(TCP采用发送应答机制,超时重传,错误校验,流量控制和阻塞管理(网络出现阻塞))
-
TCP与UDP的区别
- TCP面向连接;UDP是无连接的,即发送数据之前不需要建立连接。
- TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付。
- UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
- 每一条TCP连接只能是点到点的:UDP支持一对一,一对多和多对一和多对多的交互通信。
- TCP对系统资源要求较多,UDP对系统资源要求较少。
-
UDP
- TCP
2. TCP客户端
# 1.创建套接字
# 2.链接服务器
# 3.接收/发送数据
# 4.关闭套接字
# AF_INET是ipv4
# @Time : 2020/12/22 19:53
# @Author : Sam
# @File : TCP客户端.py
# @Software: PyCharm
'''
1.创建套接字
2.连接服务器
3.接收/发送数据
4.关闭套接字
'''
import socket
def main():
# 创建套接字 IPV4 字节流
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务器
server_ip = input('Please server IP:')
server_port = int(input("Please server PORT:"))
server_addr = (server_ip, server_port)
tcp_client.connect(server_addr)
# 接收/发送数据
send_data = input("send data:")
tcp_client.send(send_data.encode('utf-8'))
tcp_client.close()
if __name__ == '__main__':
main()
- 而在连接之后,网络助手断开就无法接收到数据了。
- 接收数据
import socket
def main():
# 创建套接字 IPV4 字节流
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务器
tcp_client.connect(('192.168.1.104', 8080))
# 发送数据
send_data = input("send data:")
tcp_client.send(send_data.encode('utf-8'))
# 接收数据
recv_data = tcp_client.recv(1024)
# print(recv_data) # b'******'
print('接收到的数据:%s'%(recv_data.decode('utf-8')))
tcp_client.close()
if __name__ == '__main__':
main()
3. TCP服务端
TCP建立服务端步骤
• 1.socket创建套接字
• 2.bind绑定IP和port
• 3.listen使套接字变为可以被动链接
• 4.accept等待客户端的链接
• 5.recv/send接收发送数据
• 6.关闭套接字
-
其中listen常定参数为128,
-
accept返回两个值,第一个返回套接字,第二个返回客户端地址。
- 返回套接字得作用:功能监听套接字。
'''
TCP服务端
• 1.socket创建套接字
• 2.bind绑定IP和port
• 3.listen使套接字变为可以被动链接
• 4.accept等待客户端的链接
• 5.recv/send接收发送数据
• 6.关闭套接字
'''
import socket
def main():
# socket创建套接字
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind绑定IP和port
tcp_server.bind(('192.168.1.104', 7080))
# listen使套接字变为可以被动链接,套接字创建出来是为了连接别人,而非别人连接你。
tcp_server.listen(128)
# accept等待客户端的链接,accept有两个返回值
new_client_socket, client_addr = tcp_server.accept()
'''
print(new_client_socket) # 套接字
print(client_addr) # 用户端地址
'''
# 接收数据
recv_data = new_client_socket.recv(1024)
print(recv_data.decode())
# 发送数据
new_client_socket.send('Hello'.encode('utf-8'))
# 关闭套接字
new_client_socket.close()
tcp_server.close()
if __name__ == '__main__':
main()
- 优化,为客户端多次连接。
import socket
def main():
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_client.bind(('192.168.1.104', 8080))
tcp_client.listen(128)
new_client_socket, client_addr = tcp_client.accept()
while True:
recv_data = new_client_socket.recv(1024)
if recv_data.decode('utf-8') == 'bye':
break
print(recv_data.decode('utf-8'))
new_client_socket.close()
tcp_client.close()
if __name__ == '__main__':
main()
-
为用户端创建可判断断开的条件
-
recv有个解堵塞
-
当我直接断开网络调试助手的连接时,会有一个返回值。
Traceback (most recent call last):
File "D:/Python/venv/Python-web全栈开发课堂练习文件/Day5/tcp多次接收.py", line 30, in <module>
main()
File "D:/Python/venv/Python-web全栈开发课堂练习文件/Day5/tcp多次接收.py", line 19, in main
recv_data = new_client_socket.recv(1024)
ConnectionAbortedError: [WinError 10053] 您的主机中的软件中止了一个已建立的连接。
import socket
def main():
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_client.bind(('192.168.1.104', 8080))
tcp_client.listen(128)
new_client_socket, client_addr = tcp_client.accept()
while True:
recv_data = new_client_socket.recv(1024)
print(recv_data.decode('utf-8'))
new_client_socket.send('Hello'.encode('utf-8'))
new_client_socket.close()
tcp_client.close()
if __name__ == '__main__':
main()
-
故解阻塞为1.收到数据。2.关闭客户端
import socket def main(): tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcp_client.bind(('192.168.1.104', 8080)) tcp_client.listen(128) new_client_socket, client_addr = tcp_client.accept() while True: recv_data = new_client_socket.recv(1024) print(recv_data.decode('utf-8')) if recv_data: new_client_socket.send('Hello'.encode('utf-8')) else: break new_client_socket.close() tcp_client.close() if __name__ == '__main__': main()
-
连接多个客户端来服务
# @Time : 2020/12/22 22:59 # @Author : Sam # @File : tcp服务多个客户端.py # @Software: PyCharm import socket def main(): tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) while True: print("Start.........") tcp_client.bind(('192.168.1.104', 8080)) tcp_client.listen(128) new_client_socket, client_addr = tcp_client.accept() print(client_addr) while True: recv_data = new_client_socket.recv(1024) print(recv_data.decode('utf-8')) if recv_data: new_client_socket.send('Hello'.encode('utf-8')) else: break new_client_socket.close() tcp_client.close() if __name__ == '__main__': main()
-
第一个发送完之后,断开,然后连接第二个。
4. send和recv原理剖析
-
socket的发送和接收缓冲区
- 当创建一个TCP socket对象的时候会有一个发送缓冲区和一个接收缓冲区,这个发送和接收缓冲区指的就是内存中的一片空间。
-
send原理剖析
- send是不是直接把数据发给服务端?
- 不是,要想发数据,必须得通过网卡发送数据,应用程序是无法直接通过网卡发送数据的,它需要调用操作系统接口,也就是说,应用程序把发送的数据先写入到发送缓冲区(内存中的一片空间),再由操作系统控制网卡把发送缓冲区的数据发送给服务端网卡 。
-
recv原理剖析
- recv是不是直接从客户端接收数据?
- 不是,应用软件是无法直接通过网卡接收数据的,它需要调用操作系统接口,由操作系统通过网卡接收数据,把接收的数据写入到接收缓冲区(内存中的一片空间),应用程序再从接收缓存区获取客户端发送的数据。
-
send和recv原理剖析图
5. 文件下载器
-
基本逻辑
-
> 客户输入一个文件名字:demo.txt,将文件保存到本地 1. 创建套接字 2. 连接服务器 3. 输入要下载的文件名称 4. 发送文件下载请求 5. 接收服务器发送过来的数据 6. 保存数据,创建文件 7. 关闭套接字 > 服务端要返回文件的数据 1. 创建套接字 2. 绑定IP和Port 3. listen主动变被动 4. accept等待客户连接 5. 接收文件名称/发送文件数据 6. 关闭套接字
-
接收客户端程序
-
''' > 客户输入一个文件名字:demo.txt,将文件保存到本地 1. 创建套接字 2. 连接服务器 3. 输入要下载的文件名称 4. 发送文件下载请求 5. 接收服务器发送过来的数据 6. 保存数据,创建文件 7. 关闭套接字 ''' import socket def main(): tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_IP = input('Server IP:') server_Port = int(input('Server Port:')) server_Addr = (server_IP, server_Port) tcp_client_socket.connect(server_Addr) file_name = input('File Name:') # 发送文件请求,发送文件名称 tcp_client_socket.send(file_name.encode()) # 就收服务器发送过来的数据 recv_data = tcp_client_socket.recv(1024 * 1024) # 1M if recv_data: # 为服务器断开提供判断条件。 # 保存数据,创建新文件 with open('[Get]' + file_name, 'wb') as new_file: new_file.write(recv_data) tcp_client_socket.close() if __name__ == '__main__': main()
-
发送服务端程序
-
''' > 服务端要返回文件的数据 1. 创建套接字 2. 绑定IP和Port 3. listen主动变被动 4. accept等待客户连接 5. 接收文件名称/发送文件数据 6. 关闭套接字 ''' import socket def main(): tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcp_server_socket.bind(('192.168.1.104', 7070)) tcp_server_socket.listen(128) new_client_socket, client_addr = tcp_server_socket.accept() file_name = new_client_socket.recv(1024).decode() file_content = '' try: with open(file_name, 'rb') as new_file: file_content = new_file.read() except Exception as e: print(e) new_client_socket.send(file_content.encode()) new_client_socket.close() tcp_server_socket.close() if __name__ == '__main__': main()