首页 > 编程语言 > 详细

python 网络传输

时间:2019-08-13 17:06:14      阅读:65      评论:0      收藏:0      [点我收藏+]

网络开发架构


C/S架构 : 需要安装一下才能使用

  client 客户端 我们用的 需要安装的
  server 服务端


B/S架构 : 百度 博客园 谷歌 码云

  browser 浏览器
  server 服务端

b/s和c/s什么关系?

  B/S架构也是C/S架构中的一种

C/S架构的好处

  可以离线使用/功能更完善/安全性更高


B/S架构的好处

  不用安装就可以使用

  统一PC端用户的入口

 

osi五层协议

应用层       python
传输层       port udp tcp 四层路由 四层交换
网络层       ipv4 ipv6 路由器 三层交换机
数据链路层    mac arp协议 网卡 二层交换
物理层
osi五层协议
    应用层
    传输层
        tcp协议 : 效率低 面向连接\可靠\全双工的通信
            三次握手
                客户端向服务器端发送syn请求,
                服务端向客户端回复ack并发送syn请求,
                客户端接收到请求之后再回复ack表示建立连接
                由客户端的connect + 服务端的accept
            四次挥手
                客户端向服务端发送fin请求,
                服务端回复ack确认
                服务端向客户端发送fin请求,
                客户端回复ack确认
                有客户端的close和服务端的close
        udp协议 : 效率高 无连接的\不可靠
        四层交换机 四层路由器
    网络层
        ip协议(ipv4 ipv6)
        路由器\三层交换机
    数据链路层
        arp协议 地址解析协议 通过ip找到mac地址
        交换机\网卡 : 单播 广播 组播
    物理层

 

七层协议

应用层
表示层
会话层
传输层
网络层
数据链路层
物理层

 

tcp协议与 udp协议 区别

tcp协议 : 效率低 面向连接\可靠\全双工的通信

udp协议 : 效率高 无连接的\不可靠

 

三次握手

客户端向服务器端发送syn请求,
服务端向客户端回复ack并发送syn请求,
客户端接收到请求之后再回复ack表示建立

四次挥手

客户端向服务端发送fin请求,
服务端回复ack确认
服务端向客户端发送fin请求,
客户端回复ack确认

socket套接字

socket套接字充当的就是内置模块的角色

socket 套接字,它存在于传输层与应用层之间的抽象层

 

tcp协议

import socket
sk=socket.socket()          #创建一个server端口
sk.bind(("127.0.0.1",9001)) #申请操作系统的资源
sk.listen()                 #开始监听(可以接收)客户端给我的连接
conn,addr=sk.accept()       #创建连接 conn是连接信息 addr是端口号
conn.send(b"hello")         #发送内容
msg=conn.recv(1024)         #收到字节
print(msg)
conn.close()                #挥手 断开连接
sk.close ()                 #申请归还的操作系统资源

 

普通版

server

技术分享图片
import socket
sk=socket.socket()          #创建一个server端口
sk.bind(("127.0.0.1",9001)) #申请操作系统的资源
sk.listen()                 #开始监听(可以接收)客户端给我的连接
conn,addr=sk.accept()       #创建连接 conn是连接信息 addr是端口号
conn.send(b"hello")         #发送内容
msg=conn.recv(1024)         #收到字节
print(msg)
conn.close()                #挥手 断开连接
sk.close ()                   #申请归还的操作系统资源
View Code

client

技术分享图片
import socket
sk=socket.socket()
sk.connect(("127.0.0.1",9001))
msg=sk.recv(1024)
print(msg)
sk.send(b"beybey")
sk.close()
View Code

 

持续发送

server

技术分享图片
import socket
sk=socket.socket()
sk.bind(("127.0.0.1",9001))# 申请操作系统资源
sk.listen()
while True:                #为了和多个客户端进行握手
    conn,addr=sk.accept() 
    while True:
        send_msg=input(">>>")
        conn.send(send_msg.encode("utf-8"))
        if send_msg.upper()=="Q":
            break
        msg=sk.recv(1024).decode("utf-8")
        if msg.upper()=="Q":break
        print(msg)
   conn.close()
sk.close()
# str -encode(‘utf-8‘)-> bytes
# str -encode(‘gbk‘)-> bytes
View Code

client

技术分享图片
import socket
sk = socket.socket()
sk.connect(("127.0.0.1",9001))
while True
    msg=sk.recv(1024)
    msg2=msg.decode("utf-8")
    if msg2.upper()=="Q":break
      print(msg,msg2)
    send_msg=input(">>>")
    sk.send(send_msg.encode("utf-8"))
    if send_msg.upper()=="Q":break
sk.close()
View Code

 

 

udp协议

注意:UDP协议不用sk.close()

server两发两收

技术分享图片
import socket

sk = socket.socket(type = socket.SOCK_DGRAM)
sk.bind((127.0.0.1,9001))
while True:
    # print(sk.recv(1024))              # b‘Your message‘
    # print(sk.recvfrom(1024))          # (b‘Your message‘, (‘127.0.0.1‘, 60182)) 注意这个本身是个大元组
    recv_msg,addr = sk.recvfrom(1024)   # 如果这里用recv,能接收信息,但是无法获得对方IP地址和端口号。所以这里要用recvfrom同时获得消息和地址
    print(recv_msg.decode(utf-8))
    send_msg = input(>>>)
    sk.sendto(send_msg.encode(utf-8),addr)
improt socket
sk=socket.socket(type = socket.SOCK_DGRAM)
sk.bind(("127.0.0.1",9001))
while True:
    msg,addr=sk.recvfrom(1024)
    print(msg.decode("utf-8"))
    msg=input(">>>")
    sk.sendto(msg.encode(utf-8),addr)
View Code

client:三发三收,都先if

技术分享图片
import socket

sk = socket.socket(type=socket.SOCK_DGRAM)
server = (127.0.0.1,9001)
while True:
    send_msg = input(>>>)
    if send_msg.upper() == Q: break
    sk.sendto(send_msg.encode(utf-8),server)
    recv_msg = sk.recv(1024).decode(utf-8)     #此时已经有对面的IP地址和端口了,无须再recvfrom
    if recv_msg.upper() == Q: break
    print(recv_msg)
View Code

 

上述程序中导致程序阻塞的语句

input():等待,直到用户输入enter键
sk.accept():阻塞,有客户端来和我建立完连接之后
sk.connect:阻塞,直到server端结束了对一个client的服务,开始和当前client建立连接的时候
recv():阻塞,直到收到对方发过来的消息之后
recvfrom():阻塞,直到收到对方发过来的消息之后

  

粘包

粘包:两条或更多条分开发送的数据连在一起的现象

   粘包只出现在tcp协议中,因为tcp协议,多条消息之间没有边界,并且还有一大堆优化算法。

粘包导致的原因:

  1. 发送端 : 两条消息都很短,发送的间隔时间也非常短,由于优化机制就合并在一起发送了

  2. 接收端 : 多条消息由于没有及时接收,而在接收方的缓存端堆在一起导致的粘包

自定义协议

第一条数据精确地规定成4字节,由于第一条数据是第二条数据的长度,因此第二条和第三条数据也不粘了

server

技术分享图片
import socket

sk = socket.socket()
sk.bind((127.0.0.1,9001))
sk.listen()

conn,addr = sk.accept()
msg1 = input(>>>).encode(utf-8)        #注意要在len前先encode
msg2 = input(>>>).encode(utf-8)
num = str(len(msg1))
ret = num.zfill(4)
conn.send(ret.encode(utf-8))
conn.send(msg1)
conn.send(msg2)
conn.close()
sk.close()
View Code

client

技术分享图片
import socket

sk = socket.socket()
sk.connect((127.0.0.1,9001))
length = int(sk.recv(4).decode(utf-8))
msg1 = sk.recv(length)
msg2 = sk.recv(1024)
print(msg1.decode(utf-8))
print(msg2.decode(utf-8))

sk.close()
View Code

 

 

struct模块

精髓在于把第一条数据精确地规定成4字节,由于第一条数据是第二条数据的长度,因此第二条和第三条数据也不粘了。但是,当第二条数据长度很长,即第一条数据用4字节表示不下时,此方法失效,由此引出第二种方法——struct模块

 

struct.pack():把-2**23到2**23范围内的整数转化成4字节bytes

struct.unpack():把4字节bytes转化成一个元组,元组的第一项取int()就是想要的长度

 

例子

技术分享图片
import struct

num1 = 129469649
num2 = 123
num3 = 8

ret1 = struct.pack(i,num1)
print(len(ret1))
ret2 = struct.pack(i,num2)
print(len(ret2))
ret3 = struct.pack(i,num3)
print(len(ret3))

print(struct.unpack(i,ret1))
print(struct.unpack(i, ret2))
print(struct.unpack(i, ret3))
View Code

 

server

技术分享图片
import struct
import socket

sk = socket.socket()
sk.bind((127.0.0.1,9001))
sk.listen()

conn,addr = sk.accept()
msg1 = input(>>>).encode(utf-8)        #注意要在len前先encode
msg2 = input(>>>).encode(utf-8)

#使用struct.pack()把len(msg1)转化成固定长度为4的bytes
blen = struct.pack(i,len(msg1))

conn.send(blen)
conn.send(msg1)
conn.send(msg2)
conn.close()
sk.close()

# 粘包现象
# 只出现在tcp协议中,因为tcp协议 多条消息之间没有边界,并且还有一大堆优化算法
# 发送端 : 两条消息都很短,发送的间隔时间也非常短
# 接收端 : 多条消息由于没有及时接收,而在接收方的缓存短堆在一起导致的粘包

# 解决粘包问题的本质 :设置边界
View Code

client

技术分享图片
import struct
import socket

sk = socket.socket()
sk.connect((127.0.0.1,9001))

#使用struct.unpack()把接收到的4字节bytes转化成一个元组,元组的第一项就是即将接收的msg1的长度,进而保证了msg1和msg2不会粘在一起
length = struct.unpack(i,sk.recv(4))[0]

msg1 = sk.recv(length)
msg2 = sk.recv(1024)
print(msg1.decode(utf-8))
print(msg2.decode(utf-8))

sk.close()
View Code

 

基于tcp协议的文件传输

 

python 网络传输

原文:https://www.cnblogs.com/Pythonzrq/p/11346952.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!