网络收发缓冲区
1、协调读写速度、减少和磁盘交互
2、recv和send实际上是从缓冲区获取内容,和向缓冲区发送内容
recv()特性
1、如果连接断开,recv会立即结束阻塞返回空字符串
2、当接收缓存区为空时会阻塞
3、如果recv一次接收不完缓冲区内容,下次会继续接收,确保数据不丢失
send()特性
1、如果另一端不存在还试图使用send进行发送则会产生BrokenPipError异常
2、当发送缓冲区满时会阻塞
TCP粘包
产生原因:TCP传输采用字节流的方式,消息之间没有边界,如果发送的速度比接收速度快,会造成多次发送的内容被一次接收,形成意义上的误解即粘包
产生条件:当使用send快速的连续发送极有可能产生粘包
影响:如果每次发送的内容代表一个独立的意思,需要单独识别,就会产生粘包。但是如果多次发送的内容就是一个连续的整体,此时就不需要处理。
如何处理:
1、每次发送后加一个结尾标志,接收端通过标志进行判断
2、发送一个数据结构
3、每次发送中间有一个短暂的延迟(有一个间隔)
TCP接收多个客户端连接,且可以持续发送消息
1 from socket import * 2 3 sockfd = socket(AF_INET,SOCK_STREAM) #创建套接字 4 5 sockfd.bind(('127.0.0.1',9999)) #绑定地址 6 7 sockfd.listen(5) #设置监听 8 9 while True: # 等待客户端连接 10 print("Waiting for connect...") 11 connfd,addr = sockfd.accept() 12 print("Connect from",addr) 13 while True: # 消息收发 14 data = connfd.recv(1024) 15 if not data: 16 break 17 print("Receive:",data.decode()) 18 n = connfd.send(b"Receive your message") 19 print("send %d bytes"%n) 20 21 connfd.close() # 关闭套接字 22 23 sockfd.close()
TCP-server
1 from socket import * 2 3 sockfd = socket() #创建套接字 4 5 sockfd.connect(('127.0.0.1',9999)) #发起连接 6 7 while True: #消息收发 8 9 msg = input("Msg>>") 10 if not msg: 11 break 12 sockfd.sendall(msg.encode()) 13 data = sockfd.recv(1024) 14 print(data.decode()) 15 16 sockfd.close()
TCP-client
UDP服务器
1、创建套接字—-》数据报套接字
sockfd = socket(AF_INET,SOCK_DGRAM)
2、绑定服务端地址
sockfd.bind()
3、消息的收发
data,addr = sockfd.recvfrom(buffersize)
功能:接收udp消息
参数buffersize:每次最多接受消息大小
返回值:data 接收到的消息 addr 消息发送者的地址(IP号和端口号)
sockfd.sendto(data,addr)
功能:udp发送消息
参数:data要发送的消息 bytes
addr 客户端地址(地址包括IP和端口号)
返回值:发送的字节
每次接收一个报文,如果没有接收完全则丢弃没有收到的内容
4、关闭套接字
sockfd.close()
sys.argv
功能:获取来自命令行的参数,形成一个列表
以空格作为每一项分隔,如果一项中有空格则用引号表示一个整体
命令行内容作为字符串传入
1 from socket import * 2 3 HOST = '0.0.0.0' 4 PORT = 8888 5 ADDR = (HOST,PORT) 6 7 sockfd = socket(AF_INET,SOCK_DGRAM) # 创建套接字 8 9 sockfd.bind(ADDR) # 绑定地址 10 11 while True: # 消息收发 12 data,addr = sockfd.recvfrom(1024) 13 print("Receive from %s:%s"%(addr,data.decode())) 14 sockfd.sendto("已经收到消息".encode(),addr) # 要发送的消息和目标地址 15 16 sockfd.close()
UDP-server
UDP客户端
1、创建套接字
sockfd = socket(AF_INET,SOCK_DGRAN)
2、消息收发
收:data,addr = sockfd.recvfrom(buffersize)
发:sockfd.sendto(data,addr)
data,addr = sockfd.recvfrom(1024)
sockfd.sendto(data.encode(),(“192.168.191.3”,8888))
3、关闭套接字
sockfd.close()
1 from socket import * 2 import sys 3 4 # 命令行输入服务器地址 5 if len(sys.argv) < 3: 6 print(''' 7 argv is error !! 8 请在终端输入 9 python3 udp_client.py 127.0.0.1 8888 10 ''') 11 raise 12 13 HOST = sys.argv[1] 14 PORT = int(sys.argv[2]) 15 ADDR = (HOST,PORT) 16 17 sockfd = socket(AF_INET,SOCK_DGRAM) # 创建套接字 18 19 while True: 20 data = input("消息:") 21 if not data: # 如果收到空消息则退出 22 break 23 sockfd.sendto(data.encode(),ADDR) 24 data,addr = sockfd.recvfrom(1024) 25 print("从服务端收到:",data.decode()) 26 27 sockfd.close()
UDP-client
TCP流式套接字和UDP数据报套接字区别
1、流式套接字采用字节流的方式传输数据,而数据报套接字以数据报形式传输
2、TCP会产生粘包现象,UDP消息是有边界的不会粘包
3、TCP传输是建立在连接的基础上,保证传输的可靠性,而UDP一次接收一个数据报,不保证完整性
4、TCP需要依赖listen、accept建立连接,UDP不用
5、TCP收发消息使用recv、send、sendall。UDP使用recvfrom、sendto
socket模块的套接字属性
(s表示一个套接字对象)
s.type 获取套接字类型 # SocketKind.SOCK_STREAM 流式套接字
s.family 获取地址族类型 # AddressFamily.AF_INET 获取地址族类型
s.fileno() 获取套接字的文件描述符(每一个IO操作系统都会为其分配一个不同的正整数,该正整数即为此IO操作系统的文件描述符)
s.getsockname() 获取套接字绑定的地址 # (‘192.168.191.3’, 8888)
s.getpeername() 获取连接套接字另一端的地址 # (‘192.168.191.3’, 7826)
s.setsockopt(level,optname,value) 设置套接字选项,丰富修改原有套接字功能
参数: level 设置选项的类型 optname 每个选项类型中的子选项 value 为选项设置值
s.getsockopt(level,optname) 获取套接字选项的值
1 from socket import * 2 s = socket() 3 print(s.type) # SocketKind.SOCK_STREAM 流式套接字 4 print(s.family) # AddressFamily.AF_INET 获取地址族类型 5 print(s.fileno()) # 376 6 s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) # 设置端口可重用 7 print(s.getsockopt(SOL_SOCKET,SO_REUSEADDR))# 获取选项值 1 8 s.bind(("192.168.191.3",8888)) 9 print(s.getsockname()) # 获取绑定的地址 ('192.168.191.3', 8888) 10 s.listen() 11 c,addr = s.accept() # addr也是链接客户端的地址 12 print(c.getpeername()) # ('192.168.191.3', 7826)获取链接套接字客户端地址 13 data = c.recv(1024) 14 print(data) # b'i' 15 c.close() 16 s.close()
View Code
套接字应用之广播
一点发送多点接收
目标地址:广播地址,每个网段类最大的地址
172.60.50.255 —-》<broadcast>
format() 合并字符串
1 # -*- coding:utf-8 -*- 2 3 from socket import * 4 s = socket(AF_INET,SOCK_DGRAM) # 创建一个数据报套接字 5 s.setsockopt(SOL_SOCKET,SO_BROADCAST,1) # 设置为可以接收广播 6 s.bind(('',9999)) # 绑定IP地址 7 while True: 8 try: 9 msg,addr = s.recvfrom(1024) 10 print("从{}获取信息:{}".format(addr,msg.decode())) 11 except KeyboardInterrupt: 12 print("接收消息结束") 13 break 14 except Exception as e: 15 print(e) 16 s.close()
广播接收
1 from socket import * 2 from time import sleep 3 dest = ('192.168.191.3',9999)# 设置广播地址 4 s = socket(AF_INET,SOCK_DGRAM) # 创建一个数据报套接字 5 s.setsockopt(SOL_SOCKET,SO_BROADCAST,1) #设置套接字可以发送接受广播 6 while True: 7 sleep(1) 8 s.sendto("我叫凌逆战!".encode(),dest) 9 s.close()
广播发送
TCP应用之HTTP传输
http协议–>超文本传输协议 应用层协议
用途:网页的获取,基于网站的数据传输,基于http协议的数据传输
特点
1、应用层协议。传输层使用tcp传输
2、简单灵活,和多种语言对接方便
3、无状态协议,不记录用户的通信内容
4、http1.1—->http2.0 成熟稳定
工作模式:
使用http双方均遵守http协议规定发送接收消息体
请求方,根据协议组织请求内容给对象
服务方,收到内容按照协议解析
服务方,将回复内容按照协议组织发送给请求方
请求方,收到回复根据协议解析
http请求(Request) 请求格式
1、请求行(熟悉格式及作用)
1、提供具体的请求类别,请求内容
GET /index.html HTTP/1.1
请求类别 请求内容 协议版本
请求种类 : GET 获取网络资源
POST 提交一定的附加数据,得到返回 结果
HEAD 获取响应头
PUT 更新服务器资源
DELETE 删除服务器资源
CONNECT 预留
TRACE 测试
OPTIONS 获取服务器性能
2、请求头 :对请求内容的具体描述
1、以键值对的形式对请求信息进行描述
e.g.
Accept: text/html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: max-age=0
Connection: keep-alive
3、空行
4、请求体 提交具体的请求参数
(GET参数,或者POST提交的内容)
http相应 Response 响应格式
1、响应行 反馈具体的响应情况
HTTP/1.1 200 OK
版本信息 响应码 附加信息
响应码 : 1xx 提示信息 表示请求已经接受
2xx 响应成功
3xx 响应需要重新请定向
4xx 客户端错误
5xx 服务器错误
常见响应码 : 200 成功
404 请求页面不存在
401 没有访问权限
500 服务器发生未知错误
503 服务器暂时无法执行
响应头 对响应信息的具体描述
e.g.
Cache-Control: private
Connection: Keep-Alive
空行
响应体:将客户想要的内容进行返回
要求 :
知道http作用
掌握http协议,请求和相应的格式以及每一部分做什么
掌握http协议中请求的基本类型和作用
知道http协议响应码的类型和表达含义
了解通过http协议请求网页的流程
补充知识点:
1、在终端运行python 1.py hahah
import sys print(sys.argv) # ['1.py', 'hahah']
接收文件
1 from socket import * 2 3 s = socket() 4 5 s.connect(('172.60.50.181',8888)) 6 7 filename = s.recv(1024).decode() 8 9 f = open('/home/tarena/'+filename,'wb') 10 11 while True: 12 data = s.recv(1024) 13 if data == b'##': 14 break 15 f.write(data) 16 17 s.send("接收完成".encode()) 18 19 f.close() 20 s.close()
recv_file
发送文件
1 from socket import * 2 from time import sleep 3 4 s = socket() 5 6 s.bind(('0.0.0.0',8888)) 7 s.listen(5) 8 9 c,addr = s.accept() 10 print("Connect from ",addr) 11 12 f = open('img.jpg','rb') 13 #将文件名称告知对方 14 c.send('img.jpg'.encode()) 15 sleep(0.1) 16 17 while True: 18 data = f.read(1024) 19 if not data: 20 break 21 c.send(data) 22 23 sleep(0.1) 24 c.send('##'.encode()) 25 26 data = c.recv(1024) 27 print(data.decode()) 28 29 f.close() 30 c.close() 31 s.close()
接收文件
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/159333.html