(二)udp,tcp粘包,广播,HTTP

recv()特征
1.如果连接端断开,recv会立即结束阻塞返回空字符串
2.当接收缓冲区为空时会阻塞
3.如果recv一次接收不完缓冲区内容,下次会继续接收,确保数据不丢失

send()特征
1.如果另一端不存在还试图使用send进行发送,则会产生BrokenPeError异常 
2.当发送缓冲区满时会阻塞

网络收发缓冲区
*缓冲区的功能 :协调读写速度,减少和磁盘交互
recv 和 send 实际上是从缓冲区获取内容,和向缓冲区发送内容

tcp粘包
产生原因: tcp传输采用字节流的方式,消息之间没有边界,如果发送和接受速度不匹配,
      会造成多次发送的内容被一次接受,形成意义上的误解即粘包
产生条件:当使用send快速的连续发送极有可能产生粘包
影响:如果每次发送的内容代表一个独立的意思,此时产生粘包需要处理,
     但是如果多次发送的内容本身就是一个连续的整体,此时就不需要处理。

如何处理:
1.每次发送后加一个结尾标志,接收端通过标志进行判断
2.发送一个数据结构
3.每次发送中间有一个短暂的延迟

基于udp的通信
服务端
1.创建套接字 --->> 数据报套接字
       sockfd = socket(AF_INET,SOCK_DGRAM)

2.绑定服务端地址
       sockfd.bind()
3.消息的收发
    data,addr = recvfrom(buffersize)
    功能:接受udp
    消息参数:每次最多接收消息的大小
    返回值:data 接收到的消息
                 addr 消息发送者的地址

sendto(data,addr)
功能:udp发送消息
参数:data要发送的消息 bytes
     addr 目标地址
返回值:发送的字节

4.关闭套接字

sockfd.close()

cookie 
sys.argv
功能:获取来自命令行的参数,形成一个列表
* 以空格作为每一项分隔,如果一项中有空格则用引号表示一个整体
* 命令行内容均作为字符串传入

from socket import * 
import sys 
#从命令行传入ip和端口
HOST = sys.argv[1]
PORT = int(sys.argv[2])
ADDR = (HOST,PORT)
sockfd = socket(AF_INET,SOCK_DGRAM)#创建数据报套接字
sockfd.bind(ADDR)#绑定地址
while True:
    data,addr = sockfd.recvfrom(5)  #接受消息
    print("Receive from %s:%s"%(addr,data.decode()))
    sockfd.sendto("收到你的消息".encode(),addr)  #发送消息
sockfd.close()#关闭套接字
from socket import * 
import sys 
if len(sys.argv) < 3:
    print('''
        argv is error !!
        run as 
        python3  udp_client.py 127.0.0.1 8888
        ''')
    raise 
HOST = sys.argv [1]
PORT = int(sys.argv[2])
SERVER_ADDR = (HOST,PORT)
sockfd = socket(AF_INET,SOCK_DGRAM)#创建套接字
while True:
    data = input("消息:")
    if not data:
        break   
    sockfd.sendto(data.encode(),SERVER_ADDR) #给服务器发送  
    data,addr = sockfd.recvfrom(1024)#收到服务器回复
    print("从服务器收到:",data.decode())
sockfd.close()

udp客户端
1.创建套接字
2.消息收发
3.关闭套接字

from socket import *
sockfd = socket(AF_INET,SOCK_STREAM)#创建tcp套接字
sockfd.bind(("127.0.0.1",8888))#绑定IP和端口
sockfd.listen(5)#设置监听
while True:  
    print("Waiting for connect....")
    connfd,addr = sockfd.accept()  #等待客户端链接
    print("Connect from",addr)
    while True:  
        data = connfd.recv(1024)   #接收
        if not data:
            break
        print("Receive message >>",data.decode())    
        n = connfd.send(b"Receive your message\n")   #发送
        print("Send %d bytes data"%n)
    connfd.close()    #关闭套接字
sockfd.close() 
from socket import * 
sockfd = socket()#创建套接字 tcp 默认参数即可 
sockfd.connect(('127.0.0.1',8888))#发起链接请求
while True:
    data = input("发送>>")
    if not data:
        break 
    sockfd.send(data.encode())  #发送消息 bytes格式
    data = sockfd.recv(1024).decode()
    print(data)
sockfd.close()#关闭套接字

 tcp流式套接字 和 udp数据报套接字 区别
 1.流式套接字采用字节流的方式传输数据,而数据报套接字以数据报形式传输
 2.tcp会产生粘包现象,udp消息是有边界的不会粘包
 3.tcp传输是建立在连接的基础上,保证传输的可靠性,而udp一次接受一个数据报,不保证完整性
 4.tcp需要依赖listen accept建立连接,udp不用
 5.tcp收发消息使用recv send     udp用recvfrom sendto

补充
sendall()
功能:同send() 作为tcp消息发送
参数:同send() 
返回值:发送成功返回None,发送失败返回异常

socket模块和套接字属性
(s表示一个套接字对象)
s.type : 获取套接字类型
s.family:获取地址族类型
s.fileno()
功能:获取套接字的文件描述符
文件描述符:每一个IO操作系统都会为其分配一个不同的正整数,该正整数即为此IO操作的文件描述符
s.getsockname()
功能:获取套接字绑定地址
s.getpeername()
功能:获取连接套接字另一端的地址
s.setsockopt(level,optname,value)
功能:设置套接字选项 丰富修改原有套接字功能
参数:lever : 获取选项的类型
       optname:每个选项类型中的子选项

          value:为选项设置值

from socket import *
s = socket()
print(s.type) #获取套接字类型
print(s.family) #获取地址族类型
print(s.fileno()) #获取文件描述符
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)#设置端口可重用
print(s.getsockopt(SOL_SOCKET,SO_REUSEADDR)) #获取选项值
s.bind(('172.60.50.93',8888))
print(s.getsockname()) #获取绑定地址
s.listen(5)
c,addr = s.accept()
print(c.getpeername())#获取链接端地址
data = c.recv(1024)
print(data)
c.close()
s.close()

udp套接字应用之广播
一点发送多点接收
目标地址: 广播地址,每个网段内最大的地址
172.60.50.255  --->> <broadcast>

cookie
format()
功能:合成字符串

from socket import * 
s = socket(AF_INET,SOCK_DGRAM) #创建套接字
s.setsockopt(SOL_SOCKET,SO_BROADCAST,1) #设置可以接收广播
s.bind(('',9999)) #绑定端口
while True:
    try:
        msg,addr = s.recvfrom(1024)
        print("从{}获取信息:{}".format(addr,msg.decode()))
    except KeyboardInterrupt:
        print("接收消息结束")
        break 
    except Exception as e:
        print(e)
s.close() 
from socket import * 
from time import sleep 
dest = ('172.60.50.255',9999) #设置广播地址
s = socket(AF_INET,SOCK_DGRAM)
s.setsockopt(SOL_SOCKET,SO_BROADCAST,1) #设置套接字可以发送接受广播
while True:
    sleep(2)
    s.sendto("加油,比利时!!".encode(),dest)
s.close()

tcp应用之HTTP传输
http协议 --->> 超文本传输协议  应用层协议
用途:网页的获取,基于网站的数据传输
     基于http协议的数据传输
特点:
    1.应用层协议,传输层使用tcp传输
    2.简单灵活,和多种语言对接方便
    3.无状态协议,不记录用户的通信内容
    4.成熟稳定 http1.1
工作模式:
* 使用http双方均遵循http协议规定发送接收消息体
* 请求方,根据协议组织请求内容发送给对方
* 服务方,收到内容按照协议解析
* 服务方,将回复内容按照协议组织发送给请求方
* 请求方,收到回复根据协议解析

http请求
http响应

作业:写一个tcp服务端和客户端,完成一个文件的传输过程
    了解http协议更多能容
read -->  send
recv -->   write
 

猜你喜欢

转载自blog.csdn.net/zh__quan/article/details/81045352