【2022-08-05】Python网络编程(二)
Python网络编程(二)
TCP/UDP协议
- TCP/IP协议中的传输层协议:
- TCP,传输控制协议
- UDP,用户数据报协议
- TCP协议:
- TCP是面向连接的、可靠的进程到进程通信的协议
- TCP提供全双工服务,即数据可以同一时间双向传输
- TCP报文段:TCP将若干个字节构成一个分组,叫报文段,TCP报文段封装在IP数据报中
- UDP协议:UDP协议是无连接、不保证可靠性的传输层协议。发送端不关心发送的数据是否到达目标主机、数据是否出错等,收到数据的主机也不会告诉发送方是否收到了数据,它的可靠性由上层协议来保障。传输数据速度更快,效率更高
TCP三次握手
- 第一次握手:客户端发送syn包(seq=x)到服务器,并进入SYN_SENT状态,等待服务器确认; 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(seq=y),即SYN+ACK包,此时服务器进入SYN_RECV状态; 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。 握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。
  
TCP四次挥手
- 与建立连接的“三次握手”类似,断开一个TCP连接则需要“四次握手”。 第一次挥手:主动关闭方发送一个FIN,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不 会再给你发数据了(当然,在fin包之前发送出去的数据,如果没有收到对应的ack确认报文,主动关闭方依然会重发这些数据),但是,此时主动关闭方还可 以接受数据。 第二次挥手:被动关闭方收到FIN包后,发送一个ACK给对方,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号)。 第三次挥手:被动关闭方发送一个FIN,用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会再给你发数据了。 第四次挥手:主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。
  
常见的TCP/UDP端口
TCP端口:
- FTP:20/21 FTP服务器所开发的控制端口
- TELNET:23 用于远程登录,可以远程控制管理目标计算机
- SMTP:25 SMTP服务器开放的端口用于发送邮件
- HTTP:80 超文本传输协议
- POP3:110 用于邮件的接收
UDP端口:
- TFTP:69 简单文件传输协议
- RPC:111 远程过程调用
- NTP:123 网络时间协议
socket套接字
基于文件类型的套接字家族
	套接字家族的名字:AF_UNIX
基于网络类型的套接字家族
	套接字家族的名字:AF_INET
"""运行程序的时候  肯定是先确保服务端运行 之后才是客户端"""
import socket
# 1.创建一个socket对象
server = socket.socket()  # 括号内什么都不写 默认就是基于网络的TCP套接字
# 2.绑定一个固定的地址(ip\port)
server.bind(('127.0.0.1', 8080))  # 127.0.0.1本地回环地址(只允许自己的机器访问)
# 3.半连接池(暂且忽略)
server.listen(5)
# 4.开业 等待接客
sock, address = server.accept()
print(sock, address)  # sock是双向通道 address是客户端地址
# 5.数据交互
sock.send(b'hello big baby~')  # 朝客户端发送数据
data = sock.recv(1024)  # 接收客户端发送的数据 1024bytes
print(data)
# 6.断开连接
sock.close()  # 断链接
server.close()  # 关机
import socket
# 1.产生一个socket对象
client = socket.socket()
# 2.连接服务端(拼接服务端的ip和port)
client.connect(('127.0.0.1', 8080))
# 3.数据交互
data = client.recv(1024)  # 接收服务端发送的数据
print(data)
client.send(b'hello sweet server')  # 朝服务端发送数据
# 4.关闭
client.close()
代码优化
1.send与recv
	客户端与服务端不能同时执行同一个
    	有一个收 另外一个就是发
       有一个发 另外一个就是收
    不能同时收或者发!!!
2.消息自定义
	input获取用户数据即可(主要编码解码)
3.循环通信
	给数据交互环节添加循环即可
4.服务端能够持续提供服务
	不会因为客户端断开连接而报错
		异常捕获 一旦客户端断开连接 服务端结束通信循环 调到连接处等待
5.消息不能为空
	判断是否为空 如果是则重新输入(主要针对客户端)
6.服务端频繁重启可能会报端口被占用的错(主要针对mac电脑)
	from socket import SOL_SOCKET,SO_REUSEADDR
	server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
7.客户端异常退出会发送空消息(针对mac linux)
	针对接收的消息加判断处理即可


半连接池
server.listen(5)
	主要是为了做缓冲 避免太多无效等待
黏包问题处理
服务端代码
    sock.recv(1024)
    sock.recv(1024)
    sock.recv(1024)
客户端代码
	 client.send(b'jason')
	 client.send(b'kevin')
     client.send(b'tony')
    
    
1.TCP特性
	流式协议:所有的数据类似于水流 连接在一起的
    	ps:数据量很小 并且时间间隔很多 那么就会自动组织到一起
2.recv
	我们不知道即将要接收的数据量多大 如果知道的话不会产生也不会产生黏包
    
import struct
# info = '下午上课 以后可能是常态!'
# print(len(info))  # 13  数据原本的长度
# res = struct.pack('i', len(info))  # 将数据原本的长度打包
# print(len(res))  # 4  打包之后的长度是4
# ret = struct.unpack('i', res)  # 将打包之后固定长度为4的数据拆包
# print(ret[0])  # 13  又得到了原本数据的长度
# info1 = '打起精神啊 下午也需要奋斗 也需要认真听 客服困难 你困我也困!!!'
# print(len(info1))  # 34
# res = struct.pack('i', len(info1))  # 将数据原本的长度打包
# print(len(res))  # 4  打包之后的长度是4
# ret = struct.unpack('i', res)
# print(ret[0])  # 34
"""
struct模块无论数据长度是多少 都可以帮你打包成固定长度
然后基于该固定长度 还可以反向解析出真实长度
    思路
        1.先将真实数据的长度制作成固定长度 4
        2.先发送固定长度的报头
        3.再发送真实数据
    
        1.先接收固定长度的报头  4
        2.再根据报头解压出真实长度 
        3.根据真实长度接收即可
"""
struct模块针对数据量特别大的数字没有办法打包!!!

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号