目录
- 网络收发缓冲区
- TCP粘包
- UDP服务端编程
- UDP客户端编程
- TCP与UDP编程区别
- 套接字对象
- UDP应用之广播
- TCP应用之HTTP服务
1. 网络收发缓冲区
套接字传输注意事项
1.监听套接字存在客户端即可发起连接
但是最终连接的处理需要accept处理
2.如果连接的另外一端退出
则 recv会立即返回空字符串并解除阻塞
3.当连接的另一端退出是,再试图 .send 发送
就会产生BrokenPipeError
网络的收发缓冲区 :
发送(send)--->发送缓冲--(操作系统)-->接受缓冲--->接受(recv)
缓冲区作用 : 协调收发(处理)速度 ; 减少交互次数
send 和 recv 实际上是和缓冲区进行交互,发送缓冲区满时就无法发送
接受缓冲区满时recv才阻塞
2. TCP粘包
产生原因 :
TCP套接字以字节流方式传输,没有消息边界
发送和接受并不能保证每次发送都及时的被接受
影响 : 如果每次发送内容表达一个独立的含义
此时可能需要处理粘包防止产生歧义
处理方法 :
1.每次发送的消息添加结尾标志(人为增加消息边界)
2. 发送数据结构体
3. 协调收发速度,每次发送后都预留接收时间,不适合大量使用(0.1s)
3. UDP服务端编程
socket ---> bind ---> recvfrom ---> sendto
个--------------------|
1.创建数据报套接字
sockfd = socket(AF_INET,SOCK_DGRAM)
2.绑定地址
sockfd.bind(addr)
3.消息收发
data , addr = sockfd.recvfrom(buffersize)
功能 : 接受UDP消息
参数 : 每次最多接受多大的消息
返回值 : data 接收到的数据 / addr 消息发送端的地址
*一次接受一个数据报,如果数据报大小大于buffersize则会丢失部分消息
sockfd.sendto(data , addr)
功能 : 发送UDP消息
参数 : data 发送的消息 (bytes格式)
addr 目标地址
返回值 : 发送的字节数
4. 关闭套接字
sockfd.close()
#udp_server.py
from socket import *
#创建数据报套接字
sockfd = socket(AF_INET,SOCK_DGRAM)
#绑定地址
sockfd.bind(('0.0.0.0',8888))
#收发消息
while True:
data = connfd.recvfrom(1024)
print("Receive from %s:%s" % (addr,data.decode()))
connfd.sendto(b'Receive your message',addr)
#关闭套接字
sockfd.close()
4. UDP客户端编程
1.创建套接字
socket(AF_INET,SOCK_DGRAM)
2.消息收发
recvfrom / sendto
3.关闭套接字
close()
注 : sys.argv : 获取命令行参数,得到一个列表
import sys
print(sys.argv)
命令本身是 argv[0]
后面的参数从argv[1]开始,默认以空格分隔
使用引号引起来的内容算作一个整体
命令行参数都以字符串放入列表
5. TCP与UDP编程区别
TCP套接字
UDP套接字
1. 流式套接字使用字节流的方式传输
数据报套接字以数据报形式传输数据
2.TCP会有粘包现象,UDP有消息边界不会粘包
3.TCP可以保证数据传输完整性,UDP则不保证
4.TCP需要进行listen/accept操作,UDP不需要
5.TCP收发消息使用新的套接字,recv send
UDP使用 recvfrom sendto
补充函数
sendall()函数
功能 : 发送TCP消息
参数 : 要发送的内容,bytes格式
返回值 : 成功返回 None 失败产生异常
6. 套接字对象
套接字对象的属性
import socket
dir(socket)
s = socket()
#设置客户端断开,端口立即释放
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
#获取设置选项值 >>> value = 1
s.getsockopt(SOL_SOCKET,SO_REUSEADDR)
s.bind(('192.168.0.1',8888))
s.listen(1024)
c,addr = s.accept()
print(c.getpeername())
属性名 | 作用 |
s.family | 获取套接字地址族类型 >>> INET … |
s.type | 获取套接字的类型 >>>SOCK_STREAM / SOCK_DGRAM … |
s.getsockname() | 获取套接字的绑定地址 >>>(‘192.168.0.1’,8888) |
s.fileno() | 获取套接字的文件描述符 >>>每一个I/O事件,操作系统都会分配一个不同的自然数作为编号,该正整数即为此I/O的文件描述符(stdin ~1;stdout ~ 2;stuerr ~ 3) |
s.getpeername() | 获取客户端连接套接字的对应地址 |
s.setsockopt(level,option,value) | 设置套接字选项,丰富或者修改套接字属性功能 .参数:level:选项类别; option : 具体选项 ; value : 选项值 |
s.getsockopt(level,option) | 返回选项值(value) ##一般在创建套接字后立即设置套接字选项 |
7. UDP应用之广播
广播 : 一点发送,多点接受
广播地址 : 192.168.207.255
广播风暴 : 一个网络中有大量的广播就会产生广播风暴占用大量带宽
影响正常的访问速度
接收端:
#broadcast_recv.py
from socket import *
#创建数据报套接字
s = socket(AF_INET,SOCK_DGRAM)
#设置套接字可以发送接受广播
s.setsockopt(SOL_SOCKET,SO_BROADCAST,1)
#固定接受端口
s.bind(("0.0.0.0",10241))
while True :
try:
msg,addr = s.recvfrom(1024)
print("从{}获取信息:{}"
.format(addr,msg.decode()))
#str.format()
except (KeyboardInterrupt,SyntaxError) :
raise
except Exception as e :
print(e)
s.close()
发送端:
#broadcast_send.py
from socket import *
from time import sleep
#设置目标地址 ipconfig
dest = ("192.168.0.255",10241)
s = socket(AF_INET,SOCK_DGRAM)
#设置能够发送广播
s.setsockopt(SOL_SOCKET,SO_BROADCAST,1)
while True:
sleep(2)
s.sendto("逺離颠倒夢想".encode(),dest)
s.close()
8. TCP应用之HTTP服务
HTTP协议:
超文本传输协议,是一个应用层协议
主要用途 :
网页数据的传输 / 也可作为一种数据传输方法!
HTTP协议的特点 :
1.应用程序协议,传输层使用TCP服务
2.简单灵活多种语言都有HTTP相关操作接口
3.无状态的协议,即不记录用户传输的信息(安全性)
4.http 1.1 支持持久连接
HTTP请求响应:
一端通过http请求的格式发送具体请求内容,另一端接受http请求
按照协议格式解析,获取真实请求后按照http协议响应格式组织回复内容
回发给请求方,完成一次数据交互
-----------------------------------------------
http 请求(request)
请求格式 :
请求行 : 具体的请求类别和请求内容
格式: GET / HTTP/1.1
请求类别 请求内容 协议版本
请求类别:表示请求的种类:
*GET(获取网络资源) *POST(提交一定的附加信息,得到返回结果)
HEAD(获取响应头) PUT(更新服务器资源) DELETE(删除服务器资源)
CONNECT(-) TRACE(用于测试) OPTIONS(用于获取服务器性能信息)
请求内容 : / (获取主页)
请求头 :对请求内容的具体描述信息
空行
请求体 :请求参数或者是提交内容
-----------------------------------------------
http 响应
响应格式 :
响应行 : 反馈响应的情况
格式 : HTTP/1.1 200 OK
协议版本 响应码 响应的附加信息
响应码 : 反应响应的具体情况
1xx(提示信息,表示请求成功) 2xx(响应成功 200等)
3xx(相应需要重定向) 4xx(客户端错误 404等)
5xx(服务端错误)
常见响应码 : 200(响应成功) 404(请求内容不存在)
401(没有访问权限) 500(服务器发生未知错误) 503(暂时无法执行)
响应头 : 对响应内容的具体描述
空行
响应体 :返回给请求端的具体内容
要求 :
1.知道什么是HTTP协议
2.请求的格式和每一部分的功能
3.响应的格式和每一部分的功能
4.常见的请求类型和响应码代表什么
#http_test.py
from socket import *
#创建TCP流式套接字
s = socket(AF_INET,SOCK_STREAM)
#绑定地址
s.bind(('0.0.0.0',8000))
#设置监听
s.listen(5)
while True:
#等待接受连接
print("waiting for connect...")
c,addr = s.accept()
print("connect from",addr)
#收发消息
data = c.recv(4096)
print("********************")
print(data) #浏览器发来的HTTP请求
print("********************")
#返回消息
data = '''HTTP/1.1 200 OK
Content-Encoding:gzip
Content-Type:text/html
<h1>Welcome to China</h1>
'''
c.send(data.encode())
c.close()
#关闭套接字
s.close()
#browser address: http://127.0.0.1:8000/
练习:
通过TCP套接字完成一个文件的发送
将一个文件从客户端发送给服务端
或者从服务端发送给客户端
文件可以是文本,也可以是图片
#recvfile.py
from socket import *
#创建TCP流式套接字
s = socket()
#绑定地址
s.bind(('127.0.0.1',8888))
#设置监听
s.listen(5)
print("waiting for connect...")
c,addr = s.accept()
print("connect from",addr)
#收发消息
f = open("recv.jpg","wb")
while True:
data = c.recv(1024)
if not data:
break
#data bytes格式
f.write(data)
f.close()
c.close()
s.close()
#sendfile.py
from socket import *
#创建TCP流式套接字
s = socket()
s.connect(("127.0.0.1",8888))
f = open('send.jpg','rb')
while True:
data = f.read(1024)
if not data :
break
s.send(data)
f.close()
s.close()