有时候从Windows上拷过来的文本文件在Linux下的某些程序(例如nmap)里无法正确解析,这是因为Windows和Linux换行符不同,此时可以用dos2unix工具转换一下。
Updates from 十月, 2015 Toggle Comment Threads | 键盘快捷键
-
jinzihao
-
jinzihao
在OJ上做输入输出量很大的题时,在main()函数开头加两句:(在C中改用malloc(1 << 20)效果相同)
12setvbuf(stdin, new char[1 << 20], _IOFBF, 1 << 20);setvbuf(stdout, new char[1 << 20], _IOFBF, 1 << 20);通过创建一个足够大的输入输出缓冲区,可以减少IO操作的频率,提高IO性能。在实际测试中最多达到了300%的性能提升。 这样看起来似乎有内存泄漏,但由于缓冲区的使命完成之时便是程序结束之时,程序结束时该段内存自然被释放,所以并不必担心内存泄漏。实际上,如果提前对该块内存进行delete[] 操作,是会造成运行时错误的。
-
jinzihao
阳光长跑app(天天课)协议分析
我校历史悠久的阳光长跑活动这学期有了一种新形式——用手机app记录跑步路径,过去傍晚时分紫操排队刷卡的盛况大概不会出现了,不光避免了拥挤,时间地点灵活了跑步也能多些新鲜感…
但似乎这app比以往的刷卡机还不靠谱,在地图上瞬间移动几百米的情况常常出现,瞬移的少还能偷些懒,瞬移得多跑步记录恐怕就要作废了…
这样不靠谱的app,大概找出点漏洞也不会很难吧…于是拿Wireshark在app上传跑步记录时抓了个包…
(具体的,用装有Wireshark的一台电脑(我这里用的raspberry pi)开热点分享网络,手机通过该热点上传跑步数据,上传过程即可被开热点的电脑上的抓包工具抓到;本想通过同一局域网下的其他电脑,在混杂模式下抓包,但是抓不到…求高人讲解…)
竟然是没有加密的http…明文的…接下来就导出看一看吧
这是登录时发送的请求:
123456789POST /index.php?app=interface&mod=User&act=loginByTypeAndId HTTP/1.1Content-Length: 198Content-Type: application/x-www-form-urlencodedHost: 182.92.227.205Connection: Keep-AliveAccept-Encoding: gzipReferer: http://182.92.227.205platform=android&appver=1.1.0&devid=865056026131165&username=********&net_env=WIFI&password=********&devname=XiaomiMI+3_4.4.4&screen_size=1920x1080&type=login&mac=14%3Af6%3A5a%3A8b%3A42%3Aae(用户名和密码就是登录app时输入的用户名和密码,此处隐去)
返回如下:
1234567891011121314HTTP/1.1 200 OKServer: nginx/1.0.15Date: Tue, 13 Oct 2015 14:37:57 GMTContent-Type: text/html; charset=utf-8Connection: closeX-Powered-By: PHP/5.3.3Set-Cookie: PHPSESSID=bucg5de9e******lbtng1mco77; path=/Expires: Thu, 19 Nov 1981 08:52:00 GMTCache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0Pragma: no-cacheServer: nginx-niugengContent-Length: 951{"token":"YjlhN2YyOGI4Mj**************YjZlNjk1N2UwYWE=","user":{"uid":"120082","email":"","nick":"u****u****u****","nick_pinyin":"","card":"","idNumber":"","name":"u****、u****u****","pinyin":"","address":"","birthday":"0","telephone":"","logo":"http://182.48.103.186/public/user_logo.jpg","type":"2","is_first_login":"1","intro":"","sex":"0","semester_id":"78","bank_name":"","bank_card":"","school":[{"id":"154","name":"u6e05u534eu5927u5b66","type":"1","description":"","create_time":"1413124157","tag":"","logo":"","memberCount":"21555","owner":"0","school_id":"28","class_id":"0"}],"class":[{"id":"263","name":"u5927u5b66u4e00u5e74u7ea7u8ba1u7b97u673au7cfb","type":"2","description":"","create_time":"1413271717","tag":"","logo":"","memberCount":"304","owner":"0","school_id":"0","class_id":"203"}],"permission":{"school_announcement":1,"class_announcement":1}},"complete_flag":"0","error_msg":"u6210u529f","error_code":"0"}(关键部分打码… u****表示一个utf-8编码的中文字符)
拿着token和PHPSESSID,就可以进一步访问其他接口了,例如列出跑步记录,上传照片、加好友,甚至可以上传跑步记录…具体的接口请自行抓取吧,似乎找到了一个作弊的办法…
一不小心跑步次数就从2次试成10次了…不幸的是没有删除记录的接口…体育老师不要打我…
另外,app内上传的图片(跑步路径/跑后自拍)可以在没有登录的情况下访问到,例如:http://182.92.227.205/index.php?app=interface&mod=Resource&act=image&md=bf4a32d699561be2ba1225ad830528df
会不会有隐私泄露的风险呢?这个md=后面的一串似乎是md5,但似乎查不出明文…不过当图床似乎还是可以的…
另外,该apk似乎并没有进行某种加密/混淆,因此可以反编译…没搞过Android开发,就去下载了一个onekey-decompile-apk,成功一键反编译…所有用到的接口都在这个文件里:AppRequestClient,可以当作API文档来看了…
-
jinzihao
对于浮点数a、b、c,if (a > b * c) 和 if (a / b > c)两种写法等价,但前者明显快于后者。
-
jinzihao
在C++的algorithm库中有一个random_shuffle()函数,可以对任意两个迭代器(iterator)之间的序列随机打乱,例:
123456789srand(time(0));int array[100];for (int i = 0; i < 100; ++i) {array[i] = i;}std::random_shuffle(array, array + 100);for (int i = 0; i < 100; ++i) {printf("%d ", array[i]);}输出的即为0~99的一个随机排列。
注意:和rand()函数一样,random_shuffle()在使用前需要用srand()设置随机数种子。 -
jinzihao
在C++中如果需要移动数组,首选string.h里面的memcpy;如果源数组和目标数组有重叠,则改用string.h里面的memmove;尽量不要手写for循环来移动数组,性能上很难超过内置函数。
-
jinzihao
(接前一条状态)另外,考虑功能相同的两种写法:
1s2Bit = ((((((((s2[k - 8] * 10 + s2[k - 7]) * 10 + s2[k - 6]) * 10) + s2[k - 5]) * 10 + s2[k - 4]) * 10 + s2[k - 3]) * 10 + s2[k - 2]) * 10 + s2[k - 1]) * 10 + s2[k];和
1s2Bit = s2[k - 8] * 100000000 + s2[k - 7] * 10000000 + s2[k - 6] * 1000000 + s2[k - 5] * 100000 + s2[k - 4] * 10000 + s2[k - 3] * 1000 + s2[k - 2] * 100 + s2[k - 1] * 10 + s2[k];在性能上后者更有优势,但差别有限(与程序的其他部分分摊后大约节省了14%的时间)
-
jinzihao
顺着前一个状态的思路,又写了一个Ver 5,这次效率提升非常明显 (Ver 1在一组数据下的总时间为3.4s,Ver 4为2.9s,而Ver5只有1.8s):
(注:在此处没有附上的外层循环代码中,变量k从n开始每次向下减9,而n在题目中可以大到5000,故绝大多数情况下k – 8 > 0,执行if {}部分,只有极少数情况执行else {}部分,即退化为Ver 4)123456789101112//Ver 5if (k - 8 > 0) {s2Bit = s2[k - 8] * 100000000 + s2[k - 7] * 10000000 + s2[k - 6] * 1000000 +s2[k - 5] * 100000 + s2[k - 4] * 10000 + s2[k - 3] * 1000 +s2[k - 2] * 100 + s2[k - 1] * 10 + s2[k];}else {for (l = 0; l < k; ++l) {s2Bit = (s2Bit + s2[l]) * 10;}s2Bit += s2[l];} -
jinzihao
以下四个版本的代码均摘自一道关于高精度乘法的题,作用均为把9位0~9的数字合并为一个长整数。其中llpow为一个预定义的数组,llpow[i]为10的i次方。
实际测试发现,Ver 4的性能最优,Ver 2次之,Ver 1较差,Ver3最差…
思考:
Ver2相比Ver1,发现for循环的判断部分(第二个参数)一定要精简,判断部分要被执行n次,而初始化部分(第一个参数)只被执行1次,这里只不过循环9次,都有可以检测到的性能差别。
Ver4相比Ver3,发现修改s2Bit是个很费时的操作,表达式能一步完成尽量不要分两步
疑问:
Ver4中(s2Bit + s2[l])的结果难道不要存到临时变量中吗?这个操作效率很高?还是编译器做了优化?还是处理器做了优化?
Ver2慢于Ver4是否因为数组(llpow10)的寻址浪费了时间呢?还是不然?1234567891011121314151617181920212223//Ver 1for (l = k; l > ((k - 9 > -1) ? k - 9 : -1); --l) {s2Bit += s2[l] * llpow10[k - l];}//Ver 2for (l = ((k - 8 > 0) ? k - 8 : 0); l < k; ++l) {s2Bit += s2[l] * llpow10[k - l];}s2Bit += s2[l];//Ver 3for (l = ((k - 8 > 0) ? k - 8 : 0); l < k; ++l) {s2Bit += s2[l];s2Bit *= 10;}s2Bit += s2[l];// Ver 4for (l = ((k - 8 > 0) ? k - 8 : 0); l < k; ++l) {s2Bit = (s2Bit + s2[l]) * 10;}s2Bit += s2[l]; -
jinzihao
在OJ上遇到结果错误(wrong answer),有时是选取的数据类型上限不够大,而上限不够大不一定会在输入数据的时候暴露出问题…有可能输入的数据在char范围内,但在程序中相乘/累加之后直接超出了long long的上限…这时可以根据需要采用取模(mod)或取符号(sgn)来控制数据范围…
-
jinzihao
在OJ上做题时,数据量大到几万的量级时,就应该果断用new/delete(或malloc/free)在堆上建对象存数据了…否则如果直接在栈上开数组,runtime error没商量…
-
jinzihao
在OJ上做和浮点数打交道的题时,一定不要吝惜使用double,不要以为float的精度对某一道题刚好够用…有时候莫名其妙的Wrong Answer就是因为精度不够…
回复