2019-05-24 15:36:32   

python pygame
### 流程: - 1.用户在线编辑或者上传代码 - 2.用户点击执行按钮 - 2.1 首先把页面的代码保存到执行目录 - 2.2 ajax调用代码运行API (注:获取访问pygame的链接) - 2.2.1 API收到请求做处理 - 2.2.1.1 运行pygame(docker)生成可访问链接 - 2.2.2 API返回链接 - 2.3 ajax页面获取到API调用结果 - 2.4 把链接加载到页面Iframe展示 &emsp; ### 上传代码和保存代码 #### 上传功能代码 视图view.py(注:只提取功能相关代码) ```python @login_required def pygame(request): upload_error='' code='' code_dir='' if request.method == 'POST': myfile=request.FILES.get('myfile', None) if myfile: myfile = request.FILES['myfile'] fs = FileSystemStorage() file_path=os.path.join('pygame',str(request.user.id)) filename = fs.save(file_path, myfile) temp_dir=os.path.join(os.path.dirname(fs.path(filename)),str(request.user.id),'tempDir') #判断临时目录是否存在存在则删除目录,创建目录 if os.path.exists(temp_dir): shutil.rmtree(temp_dir) os.mkdir(temp_dir) #判断文件是否为zip if zipfile.is_zipfile(fs.path(filename)): zip_ref = zipfile.ZipFile(fs.path(filename), 'r') zip_ref.extractall(temp_dir) is_exist_main_file=0 for fname in zip_ref.namelist(): if 'main.py' in fname: main_file=os.path.join(temp_dir,fname) is_exist_main_file=1 if is_exist_main_file: code=fs.open(main_file,'r').read() code_dir=os.path.dirname(main_file) else: upload_error='压缩包根目录下不存在main.py' zip_ref.close() fs.delete(filename) else: upload_error='文件不是压缩文件' return render(request, 'blog/pygame.html',{'upload_error': upload_error,'code':code,'code_dir':code_dir}) ``` &emsp; 模板blog/pygame.html(注:只提取功能相关代码) ```html <form method="post" class="form-inline" enctype="multipart/form-data"> {% csrf_token %} <div class="form-group"> <input type="file" id="myfile" name="myfile"> </div> <div class="form-group"> <button class="btn btn-primary" type="submit" >上传</button> </div> <label for="myfile">注意:请上传zip压缩包,且压缩包根目录包含main.py</label> </form> ``` &emsp; ### 保存功能代码 #### 视图view.py(注:只提取功能相关代码) ```python def pygame_save_code(request): code_dir=request.POST.get('codeDir','') code_content=request.POST.get('codeContent','') if not code_content: HttpResponse('{"error":"代码为空"}') #判断是否有codeDir,如果有则直接写入到当前目录,如果没有写入一个用户随机目录 if not code_dir: datetime_str=datetime.now().strftime('%Y_%m_%d_%H_%M_%S') create_dir=os.path.join(django_settings.MEDIA_ROOT,'pygame',str(request.user.id),datetime_str) os.mkdir(create_dir) code_dir=create_dir #把代码写入文件,返回写入的目录 file=open(os.path.join(code_dir,'main.py'),'w+') file.write(code_content) file.close() return HttpResponse({'{"NewCodeDir":"'+code_dir+'"}'}) ``` &emsp; #### 模板blog/pygame.html(注:只提取功能相关代码) ```html //代码编辑窗口 <textarea class="form-control line_number" id="yourcode" cols="80" rows="30"></textarea> //pygame展示窗口 <iframe id="pygame_iframe" src="" ></iframe> <button class="btn btn-success" id="pygame_run" type="button">运行</button>:write //处理代码运行逻辑 $('#pygame_run').click(function() { var code_content=$("#yourcode").val(); var codedir=$("#codeDir").val(); var token = $('input[name=csrfmiddlewaretoken]').val(); //调用保存编辑pygame代码API $.post('/blog/pygame_save_code/', { codeDir: codedir, codeContent: code_content, csrfmiddlewaretoken: token}, function(returnedData){ var obj = jQuery.parseJSON(returnedData); var NewCodeDir=obj.NewCodeDir; $("#codeDir").val(NewCodeDir); setTimeout( function() { var codedir=$("#codeDir").val(); //调用执行pygame程序的API $.post('https://pygame.ynotes.cn:3443/pygame/', { codeDir: codedir}, function(returnedData){ var obj = jQuery.parseJSON(returnedData); if(obj.hasOwnProperty('url')){ $('#pygame_iframe').attr('src', obj.url); $('#pygame_text').text('运行成功'); $('#pygame_text').css('color', 'green'); } if(obj.hasOwnProperty('error')){ console.log(obj.error); $('#pygame_text').text(obj.error); $('#pygame_text').css('color', 'red'); } }).fail(function(){ console.log("error"); }); }, 100); }).fail(function(){ console.log("error"); }); }); ``` &emsp; ### 生成访问pygame链接 #### 视图view.py ```python def index(request): code_dir=request.POST.get('codeDir','nodir') command='python /data/app/pygame/pygame_url.py '+code_dir p = subprocess.Popen(command,stdout=subprocess.PIPE,shell=True) pygame_out=p.stdout.read() return HttpResponse(pygame_out) ``` &emsp; #### 生成pygame访问链接的python脚本 pygame_url.py ```python #coding:utf-8 import sys import os import random import subprocess import hashlib import time pygame_image='codemax/pygame:v3' sample_url='https://pygame.ynotes.cn:2443/vnc_lite.html?path=?token=' if len(sys.argv) < 2: print('{ "error":"请指定pygame程序目录"}') exit(1) pygame_dir=sys.argv[1] if not os.path.isdir(pygame_dir): print('{ "error":"'+pygame_dir+'程序目录不存在."}') exit(1) pygame_main=os.path.join(pygame_dir,'main.py') if not os.path.exists(pygame_main): print('{ "error":"'+pygame_dir+'程序目录不存在文件main.py."}') exit(1) source = open(pygame_main, 'r').read() + '\n' try: code_obj=compile(source, pygame_main, 'exec') except Exception as e: print('{"error":"'+str(e)+'"}') exit(1) def get_free_random_port(): command="netstat -ltnp |grep x11vnc|awk '{ print $4}'|awk -F: '{ print $NF}'" p = subprocess.Popen(command,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,shell=True) usage_port_list=[ int(port) for port in p.stdout.read().split('\n') if port != '' ] free_post_list=set(range(5000,6000))-set(usage_port_list) return random.choice(list(free_post_list)) free_random_port=get_free_random_port() docker_out = subprocess.Popen(['docker', 'run', '-d', '-it','--cpus=0.2','-p', str(free_random_port)+':5900', '-v', pygame_dir+':/run_game', pygame_image], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) stdout,stderr = docker_out.communicate() time.sleep(1) containter_id=stdout.strip() p1 = subprocess.Popen('docker logs --tail 100 '+containter_id,stdout=subprocess.PIPE,shell=True) p2 = subprocess.Popen('grep -A 1000 Traceback',stdin=p1.stdout,stdout=subprocess.PIPE,shell=True) docker_out=p2.stdout.read() if docker_out: print('{"error":"'+docker_out.replace('\r\n','\\n').replace('"','\'')+'"}') else: token=hashlib.md5(str(free_random_port)).hexdigest() url=sample_url+token+'&password=password' print('{"url":"'+url+'"}') ``` &emsp; ### 构建pygame镜像(拥有运行pygame代码) #### DockerFile ```yaml FROM ubuntu:xenial LABEL maintainer "sheyinsong@unotes.co" EXPOSE 5900 6099 ENV \ DEBIAN_FRONTEND="nonintractive" \ X11VNC_PASSWORD="password" RUN apt-get update -y RUN apt-get install -y xvfb x11vnc python libglib2.0-0 ADD ./get-pip.py /opt/get-pip.py RUN python /opt/get-pip.py ADD ./pygame-1.9.6-cp27-cp27mu-manylinux1_x86_64.whl /opt/pygame-1.9.6-cp27-cp27mu-manylinux1_x86_64.whl RUN pip install /opt/pygame-1.9.6-cp27-cp27mu-manylinux1_x86_64.whl ADD ./start.sh /opt/start.sh ENTRYPOINT /opt/start.sh ``` #### 文件start.sh ```bash #!/bin/sh Xvfb :1 -screen 0 800x600x16 & sleep 0.1 /usr/bin/x11vnc -display :1.0 -passwd ${X11VNC_PASSWORD:-password} & sleep 0.1 DISPLAY=:1.0 export DISPLAY cd /run_game timeout 3600 python main.py ``` &emsp; ### 构建noVNC镜像(用于html访问pygaem(docker)中的GUI界面) #### DockerFile ```yaml FROM python MAINTAINER sys "sheyinsong@unotes.co" RUN apt-get update -y RUN apt-get upgrade -y RUN apt-get install -y python-numpy RUN apt-get clean RUN pip install redis RUN pip install simplejson ADD ./noVNC/ /noVNC/ CMD ["python", "/noVNC/utils/websockify/run", "--web", "/noVNC", "0.0.0.0:10240", "--target-config", "/noVNC/token.list"] ``` &emsp; #### noVNC下载链接 https://github.com/novnc/noVNC/releases
阅读 20 评论 0 收藏 0
阅读 20
评论 0
收藏 0

   2019-05-24 12:55:32   

jquery javascript
#### jQuery加载 ```javascript $(document).ready(function(){ //代码逻辑 }); ``` &emsp; #### 定义变量 ```javascript var myVar="123"; ``` &emsp; #### 获取窗口的宽高 ```javascript $(window).height(); $(window).width() ``` &emsp; #### 修改元素的宽高 ```javascript $('#myid').css("height",$(window).height()/1.2); ``` #### 窗口变化触发操作 ```javascript $(window).resize(function() { //代码逻辑 }); ``` &emsp; #### 元素点击触发操作 ```javascript $('#myid').click(function() { //代码逻辑 }); ``` &emsp; #### 元素获得焦点的操作 ```javascript $("#myid").focus(function() { //代码逻辑 }); ``` &emsp; #### 元素失去焦点操作 ```javascript $("#myid").focusout(function() { //代码逻辑 }); ``` &emsp; #### 获取元素的文本内容 ```javascript $('#myid').text(); ``` &emsp; #### 修改元素的文本内容 ```javascript $('#myid').text('OK'); ``` &emsp; #### 元素的文本内容前面添加内容 ```javascript $('#myid').prepend('OK'); ``` &emsp; #### 元素的文本内容追加内容 ```javascript $('#myid').append('OK'); ``` &emsp; #### 获取元素的value ```javascript $('#myid').val(); ``` &emsp; #### 修改元素的value ```javascript $('#myid').val("OK"); ``` &emsp; #### 解析json数据 ```javascript var obj = jQuery.parseJSON(returnedData); console.log(obj.url); ``` &emsp; #### 判断json是否包含键值 ```javascript obj.hasOwnProperty('url'); ``` &emsp; #### 修改元素的属性值src ```javascript $('#myid').attr('src', obj.url) ``` &emsp; #### post请求 ```javascript $.post('/myurl', { codeDir: codedir}, function(returnedData){ //请求成功,代码逻辑 }).fail(function(){ //请求失败,代码逻辑 }); ``` &emsp; #### 延时2秒执行代码 ```javascript setTimeout( function() { //代码逻辑 },2000); ```
阅读 4 评论 0 收藏 0
阅读 4
评论 0
收藏 0

### 介绍 终端使用的是asyncio,单线程支持并发操作。 聊天终端,暂时仅提供登陆/注销/发送在线消息/发送离线消息/帮助功能(未完待续) 登陆命令:auth userid password (userid为用户账号,用户数据存储在mysql中) 注销命令:logout 发送消息:msg userid message (支持在线和离线消息,离线消息,当对方不在线时,存储到 redis中,等用户上线之后再推送给该用户) 帮助命令:help/? ### 环境 系统:`CentOS7` 编程语言:`Python` 语言解释器:`Cpython-3.7.2` 数据库:`mysql-5.7` `redis-5.0.3` 缓存:`redis-5.0.3` ### 表结构 #### user表 ```sql CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) NOT NULL, `password` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=91 DEFAULT CHARSET=utf8; ``` ### 服务器端代码 chat_server.py ```py #coding:utf-8 ###################### # 作者: SheYinsong # # 时间: 2019-03-30 # ###################### import asyncio import aiomysql import aioredis import sys import struct import ssl import time import logging SERVER_ADDRESS = ('0.0.0.0',10000) logging.basicConfig( level=logging.DEBUG, format='%(name)s: %(message)s', stream=sys.stderr, ) log=logging.getLogger('main') #LOOP loop=asyncio.get_event_loop() #TLS配置 CERTFILE='ssl/server.crt' KEYFILE='ssl/server.key' #在线用户userid到读写Stream映射 auth_userid_map_wstream={} auth_wstream_map_userid={} #mysql 配置 db_config={ 'host':'localhost', 'port':3306, 'user':'root', 'password':'xxxxxxxx', 'db':'chat', 'charset':'utf8' } #SQL 模板 QUERY_AUTH_SQL='select password from user where id=%s' QUERY_USERID_IS_EXISTS_SQL='select id from user where id=%s' QUERY_USERNAME_OF_USERID_SQL='select username from user where id=%s' #redis配置 #redis_host='localhost' #redis_port=6379 redis_unix_socket='/var/run/redis/redis.sock' #redis KEY模板 KV_EXISTS_USERID=u'kv_exists_userid:userid:%s' KV_USERID_GET_USERNAME=u'kv_userid_get_username:userid:%s' LIST_USERMESSAGES_OF_USERID=u'list_usermessages_of_userid:userid:%s' #支持的命令列表 cmd_list=['auth','msg','logout'] #命令帮助 cmd_help=""" =============================================== | | | 命令使用说明: | | | =============================================== |命令 参数 参数 (说明) | =============================================== |auth UID PASSWORD (登录系统) | |msg UID MESSAGE (给用户发送消息) | =============================================== |命令 (说明) | =============================================== |logout (退出) | =============================================== """ async def get_custom_time_string(t_format="%Y-%m-%d %X"): """获取指定格式的时间字符串 默认格式为"%Y-%m-%d %X" """ return time.strftime(t_format) async def get_db_pool(): """获取mysql连接池""" pool = await aiomysql.create_pool(**db_config) return pool async def get_redis_pool(): """获取redis连接池""" pool = await aioredis.create_pool( redis_unix_socket, minsize=5, maxsize=10) return pool async def db_query(sql): """mysql执行查询操作""" pool = await get_db_pool() results=() async with pool.acquire() as conn: async with conn.cursor() as cur: log.debug(f'查询数据库,SQL->[ {sql} ]') await cur.execute(sql) results = await cur.fetchall() pool.close() await pool.wait_closed() return results async def redis_query(cmd,*args): """redis执行查询操作""" pool=await get_redis_pool() with await pool as conn: results =await conn.execute(cmd,*args) pool.close() await pool.wait_closed() return results async def redis_dml(cmd,*args): """redis执行增删改操作""" pool=await get_redis_pool() with await pool as conn: await conn.execute(cmd,*args) pool.close() await pool.wait_closed() async def get_username_of_userid(userid): """获取userid对应的用户名""" if await redis_query('exists',KV_USERID_GET_USERNAME % userid): username=await redis_query('get',KV_USERID_GET_USERNAME % userid) return username.decode('utf-8') else: res=await db_query(QUERY_USERNAME_OF_USERID_SQL % userid) if res: username=res[0][0] await redis_dml('set',KV_USERID_GET_USERNAME % userid,username) return username return '' async def get_userid_of_wstream(wstream): """通过writestream获取userid""" try: userid=auth_wstream_map_userid[wstream] return userid except KeyError: return -1 async def get_wstream_of_userid(userid): """通过userid获取writestream""" try: write_stream=auth_userid_map_wstream[userid] return write_stream except KeyError: return '' async def write_data(writer,data): """发送数据""" b_data=bytes(data,encoding='utf-8') b_datasize=struct.pack('H',len(b_data)) try: writer.write(b_datasize+b_data) await writer.drain() return True except: await clean_wstream(writer) return False async def read_data(reader): """读取数据""" try: length=struct.unpack('H',await reader.read(2))[0] b_data=await reader.read(int(length)) return b_data.decode('utf-8') except Exception as e: log.debug(f'读取客户端数据异常:[{e}]') return '' async def clean_wstream(writer): """清理客户端登陆信息和关闭stream""" userid=await get_userid_of_wstream(writer) if userid != -1: try: del auth_userid_map_wstream[userid] except: pass try: del auth_wstream_map_userid[writer] except: pass writer.close() async def user_auth(*args): """用户认证""" userid=int(args[0]) pwd=args[1] sql=QUERY_AUTH_SQL % (userid) res=await db_query(sql) if res: if res[0][0] == pwd: return True return False async def userid_is_exists(userid): """"判断userid是否存在""" if await redis_query('exists',KV_EXISTS_USERID % userid): return True else: res=await db_query(QUERY_USERID_IS_EXISTS_SQL % userid) if res: await redis_dml('set',KV_EXISTS_USERID % userid,'') return True return False async def userid_is_online(userid): """判断用户是否在线""" try: writer=auth_userid_map_wstream[userid] return True except KeyError: return False async def offline_userid(operator_type,*args): """下线用户""" userid=int(args[0]) try: writer=auth_userid_map_wstream[userid] if operator_type == 0: msg='有用户登录您的账号,您已被挤下线!' elif operator_type == 1: msg='您已退出登录!' else: msg='您已退出系统!' await write_data(writer,msg) except Exception as e: log.debug(e) finally: try: del auth_userid_map_wstream[userid] except: log.debug('auth_userid_map_wstream 删除失败') try: del auth_wstream_map_userid[writer] except: log.debug('auth_wstream_map_userid 删除失败') async def send_user_msg(writer,*args): """发送用户消息""" to_userid=int(args[0]) from_userid=auth_wstream_map_userid[writer] content=' '.join(args[1:]) if not await userid_is_exists(to_userid): msg='系统不存在该userid!' await write_data(writer,msg) return from_username=await get_username_of_userid(from_userid) to_username=await get_username_of_userid(to_userid) custom_time=await get_custom_time_string() send_content=f'{custom_time}\n[ {from_username}|UID:{from_userid} ]:{content}' if to_userid == from_userid: send_content=f'{custom_time}\n[ {from_username}|UID:{from_userid} ]:{content}' await write_data(writer,send_content) return if await userid_is_online(to_userid): to_writer=auth_userid_map_wstream[to_userid] if await write_data(to_writer,send_content): await write_data(writer,send_content) return #用户不在线,发送离线消息 print("用户不在线,发送离线消息") await redis_dml('rpush',LIST_USERMESSAGES_OF_USERID % to_userid,send_content) await write_data(writer,f'[离线消息]\n{send_content}') async def user_is_auth(writer): """判断用户是否认证""" if writer in auth_wstream_map_userid.keys(): return True return False async def get_offline_msg_of_userid(userid): "获取userid对应的离线消息" return await redis_query('lrange',LIST_USERMESSAGES_OF_USERID % userid,0,-1) async def push_offline_msg(writer,*args): """推送离线消息""" userid=int(args[0]) user_offline_messages_list=await get_offline_msg_of_userid(userid) for user_offline_message in user_offline_messages_list: await write_data(writer,user_offline_message.decode('utf-8')) await redis_query('del',LIST_USERMESSAGES_OF_USERID % userid) async def update_auth(writer,*args): """更新auth_userid_map_wstream和auth_wstream_map_userid""" userid=int(args[0]) auth_userid_map_wstream[userid]=writer auth_wstream_map_userid[writer]=userid async def check_args_validity(writer,cmd,*args): if cmd == 'auth': if len(args) != 2: msg='提示:认证格式: [ auth userid pwd ]' await write_data(writer,msg) return False try: userid=int(args[0]) except: msg='userid为整数!' await write_data(writer,msg) return False elif cmd == 'msg': if len(args) < 2: msg='提示:消息格式: [ msg userid content ]' await write_data(writer,msg) return False try: to_userid=int(args[0]) except: msg='userid为整数!' await write_data(writer,msg) return False return True async def handler_client(reader,writer): """处理客户端连接""" address=writer.get_extra_info('peername') log=logging.getLogger('echo_{}_{}'.format(*address)) log.debug('收到新连接') args_ok=True cmd_ok=True while True: if not await user_is_auth(writer) and cmd_ok and args_ok: msg=u'请登陆!' await write_data(writer,msg) data=await read_data(reader) if not data: break cmd=data.split(' ')[0] args=data.split(' ')[1:] if cmd == '?' or cmd == 'help': await write_data(writer,f'{cmd_help}') cmd_ok=False continue elif cmd not in cmd_list: await write_data(writer,'输入的命令不支持,请使用 help 或 ? 查看帮助!') cmd_ok=False continue cmd_ok=True if not await user_is_auth(writer): if cmd != 'auth': continue if not await check_args_validity(writer,cmd,*args): args_ok=False continue args_ok=True if await user_auth(*args): await offline_userid(0,*args) await update_auth(writer,*args) msg='认证成功!' await write_data(writer,msg) await push_offline_msg(writer,*args) else: msg='认证失败!' await write_data(writer,msg) else: if not await check_args_validity(writer,cmd,*args): args_ok=False continue args_ok=True if cmd == 'msg': await send_user_msg(writer,*args) elif cmd == 'logout': userid=await get_userid_of_wstream(writer) await offline_userid(1,userid) elif cmd == 'auth': await write_data(writer,'您已登录!') context=ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) context.load_cert_chain(certfile=CERTFILE,keyfile=KEYFILE) factory=asyncio.start_server(handler_client,*SERVER_ADDRESS,ssl=context) server=loop.run_until_complete(factory) log.debug('starting up on {} port {}'.format(*SERVER_ADDRESS)) try: loop.run_forever() except KeyboardInterrupt: pass finally: log.debug('关闭服务器.') server.close() loop.run_until_complete(server.wait_closed()) log.debug('关闭事件循环LOOP.') loop.close() ``` ### 客户端 chat_client.py ```py #coding:utf-8 ###################### # 作者: SheYinsong # # 时间: 2019-03-30 # ###################### import asyncio from aioconsole import ainput import concurrent.futures import sys import ssl import time import struct import logging #日志配置 logging.basicConfig( level=logging.DEBUG, format='%(name)s: %(message)s', stream=sys.stderr, ) log = logging.getLogger('main') #TLS配置 CERTFILE='ssl/server.crt' #chat服务器配置 SERVER_ADDRESS = ('chat.unotes.co',10000) #证书使用的chat.unotes.co域名,根据实际证书域名填写 loop = asyncio.get_event_loop() async def write_data(writer,data): """发送数据""" b_data=bytes(data,encoding='utf-8') b_datasize=struct.pack('H',len(b_data)) try: writer.write(b_datasize+b_data) await writer.drain() return True except: return False async def read_data(reader): """读取数据""" try: length=struct.unpack('H',await reader.read(2))[0] b_data=await reader.read(int(length)) return b_data.decode('utf-8') except Exception as e: log.debug(f'读取客户端数据异常:[{e}]') return '' async def read(reader,once=False): """循环读取数据""" while True: data=await read_data(reader) if data: if once: print(f'{data}\n',end='') break print(f'\x08\x08\x08{data}\n>>>',end='') async def chat_client(address): """聊天客户端""" log = logging.getLogger('chat_client') log.debug('connecting to {} port {}'.format(*address)) context=ssl.create_default_context(ssl.Purpose.SERVER_AUTH) context.load_verify_locations(CERTFILE) reader, writer = await asyncio.open_connection(*address,ssl=context) await read(reader,True) read_task=asyncio.create_task(read(reader)) while True: data=await ainput('>>>') if not data: data='?' await write_data(writer,data) try: loop.run_until_complete( chat_client(SERVER_ADDRESS) ) except: pass finally: log.debug('closing event loop') loop.close() ``` ### 运行服务器 ```bash $ python chat_server_asyncio_tls.py ``` ``` asyncio: Using selector: EpollSelector main: starting up on 0.0.0.0 port 10000 ``` ### 运行客户端1 #### 用户张三 ```bash python chat_client_asyncio_tls.py ``` ``` 请登陆! >>>auth 10001 123456 认证成功! >>>msg 10002 你好,我是张三 [离线消息] 2019-03-29 17:00:24 [ 张三|UID:10001 ]:你好,我是张三 >>> ``` ### 运行客户端2 #### 用户李四 ```bash python chat_client_asyncio_tls.py ``` ``` 请登陆! >>>auth 10002 123456 认证成功! 2019-03-29 17:00:24 [ 张三|UID:10001 ]:你好,我是张三 >>>msg 10001 你好,张三,我收到您的消息 2019-03-29 17:02:52 [ 李四|UID:10002 ]:你好,张三,我收到您的消息 >>> ``` #### 查看客户端1 ### 用户张三 ```bash $ python chat_client_asyncio_tls.py ``` ``` 请登陆! >>>auth 10001 123456 认证成功! >>>msg 10002 你好,我是张三 [离线消息] 2019-03-29 17:00:24 [ 张三|UID:10001 ]:你好,我是张三 2019-03-29 17:02:52 [ 李四|UID:10002 ]:你好,张三,我收到您的消息 ```
阅读 125 评论 0 收藏 0
阅读 125
评论 0
收藏 0

   2019-03-21 13:53:27   

php
#### 下载php(这里以php7.2为例,其它版本类似) ```bash $ wget http://cn2.php.net/get/php-7.2.16.tar.gz/from/this/mirror ```    #### 编译安装 ```bash $ tar xvf mirror $ cd php-7.2.16 $ ./configure --prefix=/opt/php72 --with-config-file-path=/opt/php72/etc --enable-mysqlnd --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd --with-gd --with-iconv --with-zlib --enable-xml --enable-bcmath --enable-shmop --enable-sysvsem --enable-inline-optimization --enable-mbregex --enable-fpm --enable-mbstring --enable-ftp --with-openssl --enable-pcntl --enable-sockets --with-xmlrpc --enable-zip --enable-soap --with-pear --with-gettext --enable-session --with-curl $ make && make install ```    #### 配置php-fpm ```bash $ cat /opt/php72/etc/php-fpm.conf ``` ``` [global] pid = /var/run/php-fpm/php72-fpm.pid error_log = /opt/php72/var/log/php-fpm.log log_level = notice [www] listen = /var/run/php-fpm/php72-fpm.sock listen.backlog = 1024 listen.allowed_clients = 127.0.0.1 listen.owner = nobody listen.group = nobody listen.mode = 0666 user = nginx group = nginx pm = dynamic pm.max_children = 300 pm.start_servers = 15 pm.min_spare_servers = 5 pm.max_spare_servers = 35 pm.max_requests = 4096 ```    #### 增加启动文件 ```bash $ cat /etc/init.d/php72-fpm ``` ``` PHPVERSION=72 PHP=php${PHPVERSION} NAME=php${PHPVERSION}-fpm DAEMON=/opt/$PHP/sbin/php-fpm CONFIGFILE=/opt/$PHP/etc/php-fpm.conf PIDFILE=/var/run/php{$PHPVERSION}-fpm.pid SCRIPTNAME=/etc/init.d/$NAME # Gracefully exit if the package has been removed. test -x $DAEMON || exit 0 d_start() { $DAEMON || echo -n " already running" } d_stop() { kill -INT `cat $PIDFILE` || echo -n " not running" } d_reload() { kill -USR2 `cat $PIDFILE` || echo -n " can't reload" } case "$1" in start) echo -n "Starting $NAME is success" d_start echo "." ;; stop) echo -n "Stopping $NAME is success" d_stop echo "." ;; reload) echo -n "Reloading $NAME configuration..." d_reload echo "reloaded." ;; restart) echo -n "Restarting $NAME is success" d_stop sleep 1 d_start echo "." ;; *) echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2 exit 3 ;; esac ```    #### 启动php-fpm ```bash $ chmod 755 /etc/init.d/php72-fpm $ /etc/init.d/php72-fpm start ``` ``` Starting php72-fpm is success. ```
阅读 23 评论 0 收藏 0
阅读 23
评论 0
收藏 0

   2019-03-18 17:59:43   

zookeeper
### 环境 三台Centos7 ```bash 主机名 IP n188 144.202.93.188 n19 144.202.80.19 n111 149.248.37.111 ```    ### 准备工作 #### 安装JDK1.8 https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html #### 配置JDK环境变量 ```bash $ tail -3 /etc/profile export JAVA_HOME=/usr/local/jdk1.8 export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar export PATH=$PATH:$JAVA_HOME/bin ``` #### 查看JDK ```bash $ java -version java version "1.8.0_201" Java(TM) SE Runtime Environment (build 1.8.0_201-b09) Java HotSpot(TM) 64-Bit Server VM (build 25.201-b09, mixed mode) ``` #### 配置hosts ```bash $ tail -3 /etc/hosts 144.202.93.188 n188 144.202.80.19 n19 149.248.37.111 n111 ```    ### 安装zookeeper #### 下载zookeeper(三台配置一样) http://zookeeper.apache.org/releases.html#download #### 配置zookeeper(三台配置一样) ```bash $ grep -v "^#" zoo.cfg tickTime=2000 initLimit=10 syncLimit=5 dataDir=/opt/zookeeper/data clientPort=2181 autopurge.purgeInterval=1 server.1=n188:2888:3888 server.2=n19:2888:3888 server.3=n111:2888:3888 ``` #### 创建数据目录(三台机器一样) ```bash $ mkdir -p /opt/zookeeper/{logs,data} ``` #### 配置myid n188机器 ```bash $ echo 1 >/opt/zookeeper/data/myid ``` n19机器 ```bash $ echo 2 >/opt/zookeeper/data/myid ``` n111机器 ```bash $ echo 3 >/opt/zookeeper/data/myid ``` 启动zookeeper #### 查看三台集群状态 n188机器 ```bash $./zkServer.sh status ZooKeeper JMX enabled by default Using config: /opt/zookeeper/bin/../conf/zoo.cfg Mode: follower ``` n19机器 ```bash $./zkServer.sh status ZooKeeper JMX enabled by default Using config: /opt/zookeeper/bin/../conf/zoo.cfg Mode: leader ``` n111机器 ```bash $./zkServer.sh status ZooKeeper JMX enabled by default Using config: /opt/zookeeper/bin/../conf/zoo.cfg Mode: follower ```
阅读 22 评论 0 收藏 0
阅读 22
评论 0
收藏 0

### 加密算法 说明:这里为了方便介绍,引入发送方A和接收方B       #### 非对称加密算法(被加密数据的安全性) `场景`:加密(RSA/DH/Elgamal/ECC)少量数据、数字签名(RSA/DSA/Elgamal) `算法`:DH RSA DSA ECC(椭圆曲线算法) Elgamal Merkle-Hellman(背包算法) Miller-Rabin(素数测试算法) 加密/解密场景 ```bash 发送方A 加密:DH/RSA/DSA公钥(接收方B)+对称加密的KEY-->密文KEY 接收方B 解密:DH/RSA/DSA私钥(接收方B)+密文KEY-->对称加密的KEY ``` 数字签名/验签场景 ```bash 发送方A 签名: 1.(SHA1/MD5+明文)->摘要1 2.摘要1+(RSA/Elgamal)私钥(发送方A)-->数字签名 接收方B 验签: 1. RSA公钥(发送方A)+数字签名-->摘要1(解密出来的) 2. SHA1/MD5+明文->摘要2(接收方B自己计算的) 3. 摘要1==摘要2 ?"成功":"失败" (对比摘要1和摘要2的值是否一致) ```    #### 对称加密算法 `场景`:适合加密大数据 `算法`:AES DES 3DES PBE RC5 Blowfish 加密/解密场景 ```bash 加密过程:明文+AES/DES+对称加密的KEY->密文 解密过程:密文+AES/DES+对称加密的KEY->明文 ``` AES加密算法的Counter模式 - ECB(电子密码本模式) - CTR(计数器模式) - GCM(CTR和GMAC结合)    #### AEAD加密方式(Authenticated Encryption with Associated Data (AEAD) `介绍`:一种同时具备保密性,完整性和可认证性的加密形式 AEAD - EtM方式:加密 then MAC - MtE方式:MAC then 加密 - E&M方式:加密 and MAC 真正的AEAD - GCM=(AES-CTR模式+GMAC结合) - ChaCha20-IETF-Poly1305 - XChaCha20-IETF-Poly1305    #### 摘要算法 `算法` MD5 SHA1 MAC GMAC ```bash 摘要操作:MD5/SHA1+文本->固定长度的HASH值 ```
阅读 30 评论 0 收藏 0
阅读 30
评论 0
收藏 0

   2019-03-11 15:00:38   

网络
#### 事件   时间:`2019-03-11 9:00`   地点:`搬瓦工一台VPS`   人物:`博主、搬瓦工技术人员`   事件:`搬瓦工上的一台VPS服务器突然失联ssh登陆不了。因为上面搭建了一台邮件服务器,导致本博客的涉及到发邮件的地方都报500错误。不过没什么人访问,影响不大。`    #### 解决过程:   第一时间登陆搬瓦工控制台,重启服务器,结果还是连不上,使用不同的姿势再重试了几次,还是一样。   立马提交了工单给搬瓦工说明的情况,搬瓦工的技术要我试着重启,不行话的重装系统(傻眼)。同时推荐我去 Interactive console(控制台)重启。这句话立马提醒了我,忘了还有控制台可以进去。   立马控制台登陆VPS,看了下网卡,看到的画面是这样的。 ```bash $ ifconfig lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:83999 errors:0 dropped:0 overruns:0 frame:0 TX packets:83999 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:6722103 (6.4 MiB) TX bytes:6722103 (6.4 MiB) ``` 二话不说立马重启网卡,提示报错。 ```bash $ /etc/init.d/network restart Shutting down loopback insterface: [ OK ] Bringing up loopback insterface: [ OK ] Bringing up interface eth0: Device eth0 does not seem to be present,delaying initialization. [FAILED] ```   google了一下,都是类似这种解决方案`rm -rf /etc/udev/rules.d/70-persistent-net.rules&&restart`,试了几次,问题依旧。 于是乎,灵机一动,对比看了搬瓦工上另一台的网卡驱动模块,发现少了当前这台VPS少加载了两个驱动模块virtio_net和virtio_console 当前VPS ```bash $ lsmod |grep net net_failover 20480 1 virtio_net virtio_scsi 20480 2 virtio_pci 24576 0 virtio_ring 20480 4 virtio_scsi,virtio_pci virtio 16384 5 virtio_scsi,virtio_pci,virtio_ring ``` 搬瓦工另一台VPS ```bash $ lsmod |grep net virtio_net 36864 0 net_failover 20480 1 virtio_net virtio_console 24576 1 virtio_scsi 20480 2 virtio_pci 24576 0 virtio_ring 20480 4 virtio_net,virtio_console,virtio_scsi,virtio_pci virtio 16384 5 virtio_net,virtio_console,virtio_scsi,virtio_pci,virtio_ring ``` 然后试着手动加载这两个模块 ```bash $ modprobe virtio_net $ modprobe virtio_console ``` 再重启试试,OK,一切又回归平静。 ```bash $ /etc/init.d/network restart Shutting down interface eth0: [ OK ] Shutting down loopback interface: [ OK ] Bringing up loopback interface: [ OK ] Bringing up interface eth0: Determining IP information for eth0... done. [ OK ] ``` 购买搬瓦工服务器通道:https://bandwagonhost.com/aff.php?aff=35573
阅读 31 评论 0 收藏 0
阅读 31
评论 0
收藏 0

   2019-03-06 16:56:03   

socks5
认证阶段 首先客户端需要和服务端有个握手认证的过程,可以采用 用户名/密码 认证或者无需认证方式。 格式如下 (数字表示位数) ```bash +----+----------+----------+ |VER | NMETHODS | METHODS | +----+----------+----------+ | 1 | 1 | 1~255 | +----+----------+----------+ ``` VER 字段是当前协议的版本号,也就是 5; NMETHODS 字段是 METHODS 字段占用的字节数; METHODS 字段的每一个字节表示一种认证方式,表示客户端支持的全部认证方式。 - 0x00: NO AUTHENTICATION REQUIRED - 0x01: GSSAPI - 0x02: USERNAME/PASSWORD - 0x03: to X’7F’ IANA ASSIGNED - 0x80: to X’FE’ RESERVED FOR PRIVATE METHODS - 0xFF: NO ACCEPTABLE METHODS 服务端返回格式 ```bash +----+--------+ |VER | METHOD | +----+--------+ | 1 | 1 | +----+--------+ ``` 一般情况下服务端返回两种情况 0x05 0x00:告诉客户端采用无认证的方式建立连接; 0x05 0xff:客户端的任意一种认证方式服务器都不支持。 举个例子, 服务器无需认证的情况如下 ``` client -> server: 0x05 0x01 0x00 server -> client: 0x05 0x00 ``` 连接阶段 认证完成,客户端向服务端发送请求: ```bash +----+-----+-------+------+----------+----------+ |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | +----+-----+-------+------+----------+----------+ | 1 | 1 | 1 | 1 | Variable | 2 | +----+-----+-------+------+----------+----------+ ``` CMD 字段 command 的缩写: - 0x01:CONNECT 建立 TCP 连接 - 0x02: BIND 上报反向连接地址 - 0x03:关联 UDP 请求 RSV 字段:保留字段,值为 0x00 ATYP 字段:address type 的缩写,取值为: - 0x01:IPv4 - 0x03:域名 - 0x04:IPv6 DST.ADDR 字段:destination address 的缩写,取值随 ATYP 变化: - ATYP == 0x01:4 个字节的 IPv4 地址 - ATYP == 0x03:1 个字节表示域名长度,紧随其后的是对应的域名 - ATYP == 0x04:16 个字节的 IPv6 地址 - DST.PORT 字段:目的服务器的端口 服务端返回格式 ```bash +----+-----+-------+------+----------+----------+ |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | +----+-----+-------+------+----------+----------+ | 1 | 1 | 1 | 1 | Variable | 2 | +----+-----+-------+------+----------+----------+ ``` REP 字段 - X'00' succeeded - X'01' general SOCKS server failure - X'02' connection not allowed by ruleset - X'03' Network unreachable - X'04' Host unreachable - X'05' Connection refused - X'06' TTL expired - X'07' Command not supported - X'08' Address type not supported - X'09' to X'FF' unassigned 举个例子,客户端通过 127.0.0.1:8000 的代理发送请求 # request: VER CMD RSV ATYP DST.ADDR DST.PORT client -> server: 0x05 0x01 0x00 0x01 0x7f 0x00 0x00 0x01 0x1f 0x40 # response: VER REP RSV ATYP BND.ADDR BND.PORT server -> client: 0x05 0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x10 0x10 传输阶段 接下来就开始传输数据,socks5 服务器只做单纯的转发功能 整个过程如下 ``` 认证阶段 client -> server: 0x05 0x01 0x00 server -> client: 0x05 0x00 连接阶段 client -> server: 0x05 0x01 0x00 0x03 0x0a b'google.com' 0x00 0x50 server -> client: 0x05 0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x10 0x10 传输阶段 client -> server -> remote remote -> server -> client ``` 转载:https://zhuanlan.zhihu.com/p/28645864
阅读 27 评论 0 收藏 0
阅读 27
评论 0
收藏 0

第 1 页 / 共 8 页
 
第 1 页 / 共 8 页