2019-04-11-day030-网络编程并发
内容回顾
黏包
- tcp协议为了保证数据的可靠传输和传输效率
- 合包机制 : 连续多条短数据会合并成一条
- 拆包机制 : 一个过大的数据会在发出之前被拆成几个小包
- tcp的黏包发生在两端:
- 发送端 : 合包机制导致
- 接收端 : 接收不及时
- 发生黏包的本质:由于tcp协议流式传输的特点导致数据与数据之间边界不清晰
- 自定义协议
- struct:能够把一个任意的数字变成固定的四个字节
- 基础版本 :先发送数据的长度(固定4字节),再发送数据本身
- 进阶版本 :先发送字典的长度(固定4字节),再发送字典,再发送数据本身
总结
- 很多概念
- osi五层协议
tcp协议和udp协议 - tcp协议 三次握手 四次挥手
- 代码
- 区别
- tcp 面向连接,流式传输,慢,可靠,全双工
- udp 面向数据包,快,不可靠,无连接
- osi五层协议
- tcp协议 黏包
- 自定义协议来解决问题 struct
- 为什么会发生黏包
- tcp协议能够处理多个client的请求 - socketserver
- 验证客户端合法性 hmac/hashilib
课上代码
并发的socketserver
Server
import time
import socketserver
class Myserver(socketserver.BaseRequestHandler):
def handle(self):
conn = self.request
for i in range(200):
conn.send(('hello%s'%i).encode('utf-8'))
print(conn.recv(1024))
time.sleep(0.5)
server = socketserver.ThreadingTCPServer(('127.0.0.1',9001),Myserver)
server.serve_forever()
ClientI
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',9001))
while True:
msg = sk.recv(1024)
print(msg)
sk.send(b'byebye')
sk.close()
ClientII
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',9001))
while True:
msg = sk.recv(1024)
print(msg)
sk.send(b'byebye')
sk.close()
验证客户端的合法性
- 不是一个面向用户的 需要用户自己输入用户名和密码的
- 而是面向一台server的所有的(500台)客户端
- 都以一种我们共同的方式来进行一个验证
Server
import os
import hashlib
import socket
secret_key = b'alex sb'
#os.urandom(32) 给每一客户端发送一个随机的字符串,来保证即使数据被拦截你也不能使用这个消息
sk = socket.socket()
sk.bind(('127.0.0.1',9001))
sk.listen()
conn,addr = sk.accept()
rand = os.urandom(32)
conn.send(rand)
sha = hashlib.sha1(secret_key)
sha.update(rand)
res = sha.hexdigest()
ret = conn.recv(1024).decode('utf-8')
if ret == res:
print('是合法的客户端')
else:
print('不是合法的客户端')
conn.close()
Client
import socket
import hashlib
secret_key = b'alexsb'
sk = socket.socket()
sk.connect(('127.0.0.1',9001))
rand = sk.recv(32)
sha = hashlib.sha1(secret_key)
sha.update(rand)
res = sha.hexdigest()
sk.send(res.encode('utf-8'))
sk.close()
hmac
import os
import hmac
hmac = hmac.new(b'alex sb',os.urandom(32))
print(hmac.digest())
验证客户端的合法性_hmac
Server
import os
import hmac
import socket
secret_key = b'alex sb'
#os.urandom(32) 给每一客户端发送一个随机的字符串,来保证即使数据被拦截你也不能使用这个消息
sk = socket.socket()
sk.bind(('127.0.0.1',9001))
sk.listen()
conn,addr = sk.accept()
rand = os.urandom(32)
conn.send(rand)
hmac = hmac.new(secret_key,rand)
res = hmac.digest()
ret = conn.recv(1024)
if ret == res:
print('是合法的客户端')
else:
print('不是合法的客户端')
conn.close()
Client
import hmac
import socket
secret_key = b'alex sb'
sk = socket.socket()
sk.connect(('127.0.0.1',9001))
rand = sk.recv(32)
hmac = hmac.new(secret_key,rand)
res = hmac.digest()
sk.send(res)
sk.close()
作业_大文件的传输
Server
import json
import struct
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',9001))
sk.listen()
conn,addr = sk.accept()
len_bytes = conn.recv(4)
num = struct.unpack('i',len_bytes)[0]
str_dic = conn.recv(num).decode('utf-8')
dic = json.loads(str_dic)
with open(dic['filename'],'wb') as f:
while dic['filesize']:
content = conn.recv(2048)
f.write(content)
dic['filesize'] -= len(content)
Client
import os
import json
import struct
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',9001))
file_path = input('>>>')
filename = os.path.basename(file_path)
filesize = os.path.getsize(file_path)
dic = {'filename':filename,'filesize':filesize}
bytes_dic = json.dumps(dic).encode('utf-8')
len_bytes = struct.pack('i',len(bytes_dic))
sk.send(len_bytes)
sk.send(bytes_dic)
with open(file_path,'rb') as f:
while filesize > 2048:
content = f.read(2048)
sk.send(content)
filesize -= 2048
else:
content = f.read()
sk.send(content)
sk.close()
# 175,060,348
# 152,117,248
作业_认证+上传
Server
import json
import socket
import struct
import hashlib
def get_md5(usr,pwd):
md5 = hashlib.md5(usr.encode('utf-8'))
md5.update(pwd.encode('utf-8'))
return md5.hexdigest()
def login(conn):
msg = conn.recv(1024).decode('utf-8')
dic = json.loads(msg)
with open('userinfo', encoding='utf-8') as f:
for line in f:
username, password = line.strip().split('|')
if username == dic['user'] and password == get_md5(dic['user'], dic['passwd']):
res = json.dumps({'flag': True}).encode('utf-8')
conn.send(res)
return True
else:
res = json.dumps({'flag': False}).encode('utf-8')
conn.send(res)
return False
def upload(conn):
len_bytes = conn.recv(4)
num = struct.unpack('i', len_bytes)[0]
str_dic = conn.recv(num).decode('utf-8')
dic = json.loads(str_dic)
with open(dic['filename'], 'wb') as f:
while dic['filesize']:
content = conn.recv(2048)
f.write(content)
dic['filesize'] -= len(content)
sk = socket.socket()
sk.bind(('127.0.0.1',9001))
sk.listen()
while True:
try:
conn,addr = sk.accept()
ret = login(conn)
if ret:
upload(conn)
except Exception as e:
print(e)
finally:
conn.close()
sk.close()
Client
import os
import json
import socket
import struct
def upload(sk):
# 上传文件
file_path = input('>>>')
filename = os.path.basename(file_path)
filesize = os.path.getsize(file_path)
dic = {'filename': filename, 'filesize': filesize}
bytes_dic = json.dumps(dic).encode('utf-8')
len_bytes = struct.pack('i', len(bytes_dic))
sk.send(len_bytes)
sk.send(bytes_dic)
with open(file_path, 'rb') as f:
while filesize > 2048:
content = f.read(2048)
sk.send(content)
filesize -= 2048
else:
content = f.read()
sk.send(content)
usr = input('username :')
pwd = input('password :')
dic = {'operate':'login','user':usr,'passwd':pwd}
bytes_dic = json.dumps(dic).encode('utf-8')
sk = socket.socket()
sk.connect(('127.0.0.1',9001))
sk.send(bytes_dic)
res = sk.recv(1024).decode('utf-8')
dic = json.loads(res)
if dic['flag']:
print('登录成功')
upload(sk)
else:
print('登录失败')
sk.close()
ClientII
import os
import json
import socket
import struct
def upload(sk):
# 上传文件
file_path = input('>>>')
filename = os.path.basename(file_path)
filesize = os.path.getsize(file_path)
dic = {'filename': filename, 'filesize': filesize}
bytes_dic = json.dumps(dic).encode('utf-8')
len_bytes = struct.pack('i', len(bytes_dic))
sk.send(len_bytes)
sk.send(bytes_dic)
with open(file_path, 'rb') as f:
while filesize > 2048:
content = f.read(2048)
sk.send(content)
filesize -= 2048
else:
content = f.read()
sk.send(content)
usr = input('username :')
pwd = input('password :')
dic = {'operate':'login','user':usr,'passwd':pwd}
bytes_dic = json.dumps(dic).encode('utf-8')
sk = socket.socket()
sk.connect(('127.0.0.1',9001))
sk.send(bytes_dic)
res = sk.recv(1024).decode('utf-8')
dic = json.loads(res)
if dic['flag']:
print('登录成功')
upload(sk)
else:
print('登录失败')
sk.close()
2019-04-11-day030-网络编程并发的更多相关文章
- 网络编程 并发socketserver
网络编程 并发socketserver ipv4.ipv6 ip协议:规定网络地址的协议 B/S架构 C/S架构 bs是cs的一种 B/S是浏览器和服务端架构 C/S是客户端和服务端架构 osi七层协 ...
- UNIX网络编程——并发服务器(TCP)
在迭代服务器中,服务器只能处理一个客户端的请求,如何同时服务多个客户端呢?在未讲到select/poll/epoll等高级IO之前,比较老土的办法是使用fork来实现. 网络服务器通常用fork来同时 ...
- 网络编程并发 多进程 进程池,互斥锁,信号量,IO模型
进程:程序正在执行的过程,就是一个正在执行的任务,而负责执行任务的就是cpu 操作系统:操作系统就是一个协调.管理和控制计算机硬件资源和软件资源的控制程序. 操作系统的作用: 1:隐藏丑陋复杂的硬件接 ...
- [19/04/14-星期日] 网络编程_java.net包(InetAddress类、InetSocketAddress类、URL类)
一.概念 Java为了可移植性,不允许直接调用操作系统,而是由java.net包来提供网络功能.Java虚拟机负责提供与操作系统的实际连接. InetAddress 作用:封装计算机的IP地址和 ...
- ubuntu14.04下unix网络编程环境的配置
建议 unpv13e/README看一下,忽略一下内容 ===================================================================== 操作 ...
- 2019.04.11 第四次训练 【 2017 United Kingdom and Ireland Programming Contest】
题目链接: https://codeforces.com/gym/101606 A: ✅ B: C: ✅ D: ✅ https://blog.csdn.net/Cassie_zkq/article/ ...
- ubuntu14.04下unix网络编程 环境的配置
在ubuntu下 首先:在unpv13e文件加下 ./configure cd lib make cd ../libfree make cd ../liggai make cd .. vim lib/ ...
- UNIX网络编程——非阻塞connect:时间获取客户程序
#include "unp.h" int connect_nonb(int sockfd, const SA *saptr, socklen_t salen, int nsec) ...
- UNIX网络编程——使用select函数编写客户端和服务器
首先看原先<UNIX网络编程--并发服务器(TCP)>的代码,服务器代码serv.c: #include<stdio.h> #include<sys/types.h> ...
- 11Java网络编程
十一.网络编程 11.1 网络通信协议 网络通信协议:通信协议是对计算机必须遵守的规则,只有遵守这些规则,计算机之间才能进行通信.这就好比在道路中行驶的汽车一定要遵守交通规则一样,协议中对 ...
随机推荐
- codeforces #305 C Mike and Foam
首先我们注意到ai<=50w 因为2*3*5*7*11*13*17=510510 所以其最多含有6个质因子 我们将每个数的贡献分离, 添加就等于加上了跟这个数相关的互素对 删除就等于减去了跟这个 ...
- SQL语句汇总(二)——数据修改、数据查询
SQL语句第二篇,不说废话直接开始吧. 首先创建一张表如下,创建表的方法在上篇介绍过了,这里就不再赘述. 添加新数据: INSERT INTO <表名> (<列名列表>) VA ...
- Centos下安装cassandra
一.环境准备 环境 Centos6.5 .安装有Java JDK(https://www.cnblogs.com/wt645631686/p/8267239.html这篇文章里有安装JDK1.8的教 ...
- python爬虫——绕开杂乱无章的代码和堵住请求的302异常(2)
淘宝那次抓包,居然发现不了要抓的url位置,三星中... 不过不怕,不就是没法快点分析出包嘛,下次用phantomJS硬杠,或者有时间慢慢分析也好. 今天挑战一个稍微好爬的网站:狗搬家(误) 打开后台 ...
- LOJ #10130 点的距离
在LOJ做的第一道题. 最开始想复杂了qwq 想的是在求LCA的过程中统计向上的步数 其实此题很裸--就是求出u,v的LCA, 再分别用两点深度减去LCA的深度,再加起来就好了qwq---化简--- ...
- P3601 签到题
思路 注意到求的qiandao(x)就是\(x-\phi(x)\) 但是\(l,r\le 10^{12}\),所以不能直接杜教筛 但是\(r-l\le 10^{6}\),所以可以先筛出1e6(\(\s ...
- Could not process inbound connection: Client [/rostopic_18439_1555659423249] wants topic , ROS md5sums do not match
报错如下: [WARN] [WallTime: ', 'md5sum': '0d0edf749cdde9f3dc5639668f40e90b', 'topic': '/bp_update_feedba ...
- flex属性导图
声明:部分图片转载自 http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html?utm_source=tuicool
- Ajax+Struts2用户注册功能实现
详细请参考源码(Github):https://github.com/QQ3330447288/ajaxRegister 1.目录结构 2.截图 3.核心代码: register.jsp <sc ...
- 两个非空的<div>元素inline-block化后出现空白部分解决办法
在涉及到两个<div>元素并列显示的效果时,一般有两种方法: 1.使用float元素让元素并联显示: 2.将块状的<div>元素display设置为inline-block,使 ...