标签:监听 消息传递 except 缓存 浏览器 流式 循环调用 ase head
软件开发架构
c/s架构:
? c: 客户端
? s: 服务端
b/s架构
? b: 浏览器
? s: 服务器
服务端:24 H 不间断提供服务
客户端: 需要时找服务器提供服务
网络编程》》》》》》学习cs架构软件
并发编程:前端,数据库,框架》》》》》》开发bs架构软件
实现网络通信的前提:物理连接介质
统一的标准:协议
'''
应用层*
表示层
会话层
传输层*
网络层*
数据链路层*
物理链路层*
'''
物理链路层:
实现计算机之间物理连接,传输的都是010101010的二进制
基于电信号工作原理:只有高低电平
数据链路层(以太网协议):通讯方式基本靠吼
规定了二进制的数据分组方式
规定每个接入互联网的设备都必须有一块网卡
网络层(IP协议):
传输层(端口协议):TCP,UDP基于端口工作的协议
计算机应用程序与应用程序之间的通讯
端口(port):唯一标识一台计算机上的某一个基于网络的通讯的协议
'''
端口范围:0~65535(动态分配)
注意:0~1024通常是归操作系统分配的端口号
通常情况下,我们写的软件端口号建议起在8000之后
flask框架默认端口5000
django框架默认端口8000
mysql数据库默认端口3306
redis数据库默认端口6379
'''
TCP(流式协议,可靠协议)
三次握手四次挥手
?
UDP协议(数据报协议)
无需建立双向连接,并且传输数据不可靠,可能会出现丢包的情况
通信速度比较快,但是发送的数据不会在内存中保留!
qq用的就是udp协议
什么是socket层?
socket工作流程
# 服务端:
'''
服务器端先初始化socket,然后与端口绑定(bind),对端口进行监听(listen)
调用(accept)阻塞,等待客户端连接。
'''
# 客户端:
'''
客户端初始化socket,然后连接服务器(connect)
'''
# 通讯连接
'''
连接成功,客户端与服务器端的连接就建立好了,客户端发送数据请求,服务端接收并且处理请求,然后把回应数据发送给客户端回应
客户端读取数据,关闭连接,完成一次交互
'''
s.bind() 绑定(主机,端口号)到套接字
s.listen() 开始TCP监听
s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来
s.connect() 主动初始化TCP服务器连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
s.recv() 接收TCP数据
s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
s.recvfrom() 接收UDP数据
s.sendto() 发送UDP数据
s.getpeername() 连接到当前套接字的远端的地址
s.getsockname() 当前套接字的地址
s.getsockopt() 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() 关闭套接字
# 服务端
import socket
# 指定端口和每次数据长度
IP_PORT = ('127.0.0.1', 8080) # 电话卡
BUFSIZE = 1024
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 买电话
server.bind(IP_PORT) # 插电话卡
server.listen(5) # 待机
while True: # 接收连接循环,可以不停的接电话
conn, addr = server.accept() # 接电话 阻塞:等待客户端连接
while True: # 新增接收连接的循环,可以不断的通讯
try:
msg = conn.recv(BUFSIZE) # 听电话
if len(msg) == 0: break # 防止如果正在连接次client断开,recv发生死循环
print(msg)
conn.send(msg.upper()) # 发消息
except ConnectionResetError:
break
conn.close()
server.close()
# 客户端
import socket
IP_PORT = ('127.0.0.1', 8080) # 电话卡
BUFSIZE = 1024
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买手机
client.connect(IP_PORT) # 插卡
while True: # 循环连接
msg = input('请输入你:').strip()
if len(msg) == 0: continue
client.send(msg.encode('utf-8')) # 发送给服务端
serverback=client.recv(BUFSIZE) # 接收服务端反馈
print(serverback.decode('utf-8'))
s.close()
粘包问题
注:只有tcp才有粘包问题,因为TCP协议是流式协议
粘包的解决方法
发送数据直接先告诉对方数据大小
利用struct模块制定消息传递协议
利用struct 解决方法
发送时
接收时
案例:利用socket发送大文件
# 客户端
import socket
import struct
import json
import os
IP_PORT = ('127.0.0.1',8080)
client = socket.socket()
client.connect(IP_PORT)
file_path = r'F:\python_s7\网络编程复习\a'
file_size = os.path.getsize(file_path)
dic = {
'file_name': 'b',
'file_siz': file_size,
}
# json序列化
header_json = json.dumps(dic)
header_bytes = header_json.encode('utf-8')
# 制作字典报头
header = struct.pack('i',len(header_bytes))
# 发送报头
client.send(header)
# 发送字典数据
client.send(header_bytes)
# 发送真实内容
with open(file_path,'rb')as f:
for line in f:
client.send(line)
# 服务端
import socket
import json
import struct
IP_PORT = ('127.0.0.1',8080)
server = socket.socket()
server.bind(IP_PORT)
server.listen(5)
while True:
conn,addr = server.accept()
while True:
try:
header = conn.recv(4)
if len(header)==0:break
dic_len = struct.unpack('i',header)[0]
dic = json.loads(conn.recv(dic_len).decode('utf-8'))
file_name = dic['file_name']
file_size = dic['file_size']
recv_size = 0
with open(file_name,'wb') as f :
while recv_size<file_size:
data = conn.recv(1024)
f.write(data)
recv_size += len(data)
except ConnectionResetError:
break
"""
1.udp协议客户端允许发空
2.udp协议不会粘包
3.udp协议服务端不存在的情况下,客户端照样不会报错
4.udp协议支持并发
UDP叫数据报协议,意味着发消息都带有数据报头
udp的server不需要就行监听也不需要建立连接
在启动服务之后只能被动的等待客户端发送消息过来,客户端发送消息的时候,要带上服务端的地址
服务端在回复消息的时候,也需要带上客户端的地址
"""
# 服务端
import socket
server = socket.socket(type=socket.SOCK_DGRAM)
server.bind(('127.0.0.1', 8080))
msg, addr = server.recvfrom(1024)
print(msg.decode('utf-8'))
server.sendto(b'hello', addr)
server.close()
#客户端
import socket
client = socket.socket(type=socket.SOCK_DGRAM)
server_addr = ('127.0.0.1', 8080)
client.sendto(b'hello server baby!', server_addr)
msg, addr = client.recvfrom(1024)
print(msg, addr)
# TCP socketserver使用
import socketserver
class MyTcpSever(socketserver.BaseRequestHandler):
def handle(self):
while True:
try:
# self.request 相当于conn对象
data = self.request.recv(1204)
if len(data) == 0: break
print(data)
self.request.send(data.upper())
except ConnectionResetError:
break
if __name__ == '__main__':
sever = socketserver.ThreadingTCPServer(('127.0.0.1',8081),MyTcpSever)
sever.serve_forever()
# Tcp客户端
import socket
client = socket.socket()
client.connect(('127.0.0.1',8080))
while True:
client.send(b'hello')
data = client.recv(1024)
print(data)
# UDP socketserver使用
import socketserver
class MyUdpServer(socketserver.BaseRequestHandler):
def handle(self):
while True:
data, sock = self.request
print(data)
sock.sendto(data.upper(), self.client_address)
if __name__ == '__main__':
server = socketserver.ThreadingUDPServer(('127.0.0.1', 8080), MyUdpServer)
server.serve_forever()
# UDP 客户端
import socket
import time
client = socket.socket(type=socket.SOCK_DGRAM)
server_addr = ('127.0.0.1',8080)
while True:
client.sendto(b'hello',server_addr)
data,addr = client.recvfrom(1024)
print(data,addr)
time.sleep(1)
标签:监听 消息传递 except 缓存 浏览器 流式 循环调用 ase head
原文地址:https://www.cnblogs.com/king-home/p/10885841.html