统计学习和数据挖掘参考书

The elements of statistical learning : data mining, inference, and prediction
ISBN 9780387848570
Authors Haste, Trevor
Publisher Springer
Copyright Date c2009
Price $89.95

Applied predictive modeling
ISBN 9781461468486
Authors Kuhn, Max
Publisher Springer
Copyright Date c2013
Price $89.95

Data Mining: Practical Machine Learning Tools and Techniques
ISBN 9780120884070
Authors Witten, I. H., Frank, E. and Hall, M. A.
Publisher Springer
Copyright Date 2011
Price $75.95

感谢哥大同学提供参考。

自Java 7以来的数字证书兼容性问题

在使用JavaApns做IOS推送的时候报如下错误

javapns.communication.exceptions.
    InvalidCertificateChainException

使用Java 6和PHP就没有问题。网上粗略调查过发现是java 7以来的安全机制的问题。尝试使用如下方法解决:

使用JDK 7附带的keytool做两次转换:

.p12 到 jks:

keytool -importkeystore -destkeystore temp.jks -srckeystore src.p12 -srcstoretype PKCS12

jks 到 .p12:

keytool -importkeystore -srckeystore temp.jks -srcstoretype JKS -deststoretype PKCS12 -destkeystore dest.p12

使用新生成的p12密钥文件,一切正常。

Openstack OpenVSwitch GRE 组网下的逻辑架构

虚拟化实例(虚拟机)产生数据包并将其通过其内部的虚拟网络接口( virtual NIC)比如eth0,发送出来,并被传送到计算节点的Test Access Point (TAP)设备上。从/etc/libvirt/qemu/instance-xxxxxxxx.xml文件记录了当前设备的配置信息。

TAP设备的名称由端口ID的前11位组成(10位十六进制码和1位连字符),所以另外一种获取TAP设备名称的方法就是使用neutron命令。neutron port-list命令返回端口列表,第一项是端口ID。利用这里输出的前11个字符,我们可以得到相应TAP设备的名称。



TAP设备连接到整合网桥 br-int。该网桥连接所有实例的TAP设备以及系统内的其他网桥。在本例当中,有 int-br-eth1patch-tun接口。int-br-eth1是连接到br-eth1网桥的桥臂的一端,处理物理接口eth1上承载的VLAN。patch-tun是OpenvSwitch的内部端口,连接到br-tun网桥,用来提供GRE封装隧道网络。

网络节点侧的br-int整合网桥,集成了相应的网络功能,比如DHCP服务(dnsmsq),NS服务(dnsmsq),3层路由服务(实际上就是利用netns和iptables做的隔离),安全组和防火墙(iptables)。还有br-ext可以提供外网的接入支持。

计算节点导网络节点之间的通信,有多种方法实现。可以采用2层VLAN/Vxlan的方式(br-eth1),或者在三层上打GRE隧道(br-tun)。

MySQL 自增ID 和 UUID 做主键的初步性能研究

这几天在纠结数据表主键的设计问题,考虑使用自增ID还是UUID来做主键,数据库后端为MySQL。
首先在互联网上搜索,得到实测 Mysql UUID 性能这篇文章,他的结论是:

当数据表的引擎为MyISAM 时,自增 ID 无疑是效率最高的, UUID 效率略低,但不会低到无法接受。一旦数据引擎为 InnodB 时,效率下降非常严重,已经达到令人发指的地步。由于 InnodB 主键采用 聚集索引 ,会对插入的记录进行物理排序,而 UUID本身基本上是无序的,所以造成了巨大的 I/O 开销。所以如果使用 innodB 千万不要使用 UUID 。

结论经过我后来的测试验证基本正确,但是对这篇文章中间的测试方法不敢苟同。

其测试过程中重大错误:针对自增id的两个表的插入操作没有写入varchar字段,考虑到varchar插入的性能消耗,这一点是绝对不能够忽略的!

建立四张测试用表:

uuidtest_inno(uuid,text),
idtest_inno(id,text),
uuidtest_myisam(uuid,text),
idtest_myisam(id,text)

建立四个存储过程,测试数据量插入100 000行:

DROP PROCEDURE IF EXISTS p_uuid_inno//
CREATE PROCEDURE p_uuid_inno()
BEGIN
DECLARE i INT;
SET i=0;
WHILE i

清空这四个表:

TRUNCATE inttest_inno//
TRUNCATE uuidtest_inno//
TRUNCATE inttest_myisam//
TRUNCATE uuidtest_myisam//

执行存储过程:

call p_int_myisam()//
call p_uuid_myisam()//
call p_int_inno()//
call p_uuid_inno()//

发现执行时间巨长无比。无奈,将测试数据量缩减到1000次插入。
myisam的时间都是0.2s左右,innodb为55s左右。

考虑数据库优化,放弃ACID支持,
设置 innodb_flush_log_at_trx_commit = 2
得到:

mysql> call p_int_myisam();
Query OK, 1 row affected (2.02 sec)

mysql> call p_uuid_myisam();
Query OK, 1 row affected (2.63 sec)

mysql> call p_int_inno();
Query OK, 1 row affected (9.71 sec)

mysql> call p_uuid_inno();
Query OK, 1 row affected (13.88 sec)

再设置 innodb_flush_method = O_DIRECT
得到:

mysql> call p_int_myisam();
Query OK, 1 row affected (2.06 sec)

mysql> call p_uuid_myisam();
Query OK, 1 row affected (2.56 sec)

mysql> call p_int_inno();
Query OK, 1 row affected (7.59 sec)

mysql> call p_uuid_inno();
Query OK, 1 row affected (10.88 sec)

再设置 innodb_log_buffer_size = 8M(之前的设置是3M)
得到:

mysql> call p_int_myisam();
Query OK, 1 row affected (1.96 sec)

mysql> call p_uuid_myisam();
Query OK, 1 row affected (2.63 sec)

mysql> call p_int_inno();
Query OK, 1 row affected (5.28 sec)

mysql> call p_uuid_inno();
Query OK, 1 row affected (9.59 sec)

可以看到对innodb来说插入速度低于myisam,这与选择uuid还是自增ID做主键没有太大的关系,uuid的确要比自增ID慢但是不至于说是数量级上的慢。

Wireless路由/接入点攻击

近些年来,越来越多的用户的网络接入方式由有线转向了无线,其中不乏大量的个人用户,使用着各式各样的消费级无线路由器/无线接入点。无线安全的发展也历经了十年时间,然而这并不代表个人用户所使用的无线鉴权方式的安全性得到了很大的改善。

在最开始,我们首先来记住一句话:

任何系统都有他的薄弱之处!

无线安全等级我大致划分如下:

  • 无无线安全性设置;
  • WEP安全设置;
  • WPA/WPA2安全设置。

对于企业用户来说,接入点不使用安全性设置一点问题也没有,他们完全可以利用认证网关的方式达到安全性要求,而忽略接入点的安全性以获得更高的兼容性。对于个人用户来说,不设置接入点鉴权,就意味着将你的网络没有防范的摆在每一个人面前,除去数据被截获的担忧意外,对于一般个人用户来说更重要的是,你向运营商付费获得的带宽可以很轻易地被他人占用,或者说,被蹭网。

那么我们现在来看一下两大安全鉴权方式:

WEP

这是一个过时的方式。面对蹭网者,WEP加密仅仅是在不加密的基础上多了一层窗户纸。这层窗户纸能够帮你挡掉小白型的机会蹭网者,但是对有着丰富蹭网经验的人来说,真的是一层窗户纸而已。

这是因为WEP在设计的时候有漏洞,他不会更新IV(初始向量),导致了攻击者在截获了足够数量的数据包以后,完全可以用一定的算法计算出你的加密密钥。一般来说15000数据包是足够计算的了。

破解WEP加密,主要的时间消耗在于数据包的获取,一旦有了足够的数据包,解密只是十几秒的事情。

在没有其他因素干扰的情况下,数据包的获取速度与在线客户端网络使用量、攻击者与接入点之间的信号强度成正比。而攻击者可以使用各种注入攻击,虚假ARP请求等方式来加速获取数据包。另外,有实验表明,无客户端连接的情况下,也完全可以达成对WEP加密的接入点的攻击。

WPA/WPA2

这种加密方式与WEP相比有了很大的提高,他会定时更换随机生成的IV,就目前来说还没有一个像WEP一样的漏洞可以保证一定能够获得加密密钥。但是记住,任何系统都有薄弱点,这个薄弱点很可能就是用户自己!WPA强制使用8位以上密钥,但是如果这个密钥只是弱密码呢?笔记本把8位纯数字跑一遍也不过4个小时,更何况8个1,8个0,12345678或者年月日这种弱密码呢!WPA/WPA2的攻击方法是截获握手包并且利用预先生成的字典文件进行检测。在有客户端连接的情况下,握手包的获取速度很快,一般在5分钟以内。使用Fake Auth等方法更能加快这一过程。在我的笔记本上,Windows下的EWSA可以达到7000key/s的检测速度,弱密码跑一遍估计就是2秒钟。

那么是不是说设置一个复杂的长密码就可以高枕无忧了呢?不是这样的。现在很多家用路由器提供了快速连接WPS功能,一般是通过物理按钮完成无密钥连接。但是WPS实际上还有一个PIN码连接的功能,该功能的设计有缺陷,8位的PIN码全部跑一遍应该是(10^8)数量级,而设计缺陷使得8位PIN码被一分为三:4位第一部分,3位第二部分,1位校验位。所以实际上的数量级是:(10^4+10^3=11000),而平均期望为5500。

按照6s一个PIN码的保守估计,平均用时9小时就一定能够获得真实的PIN码和密钥。而考虑到实际过程当中,会使用加强天线等方式,以及各个厂家的PIN码其实是有规律可循的,总体时间可以控制在2小时以内。不管设置的密钥有多么长,多么复杂,一切皆是无用。

Java PrintWriter flush属性

在做当前项目的socket开发时候,按照惯例使用BufferedReader和PrintWriter做输入输出,发现使用telnet连接服务器的时候,客户端输入正常,服务器输出正常 ,但是客户端没有接收到服务器的消息。考虑过是和Flush有关的问题,依稀记得以前看到过有关PrintWriter的介绍,是在调用println等方法的时候自动flush的,于是一直没仔细研究。研究过各个方面后以及其他代码之后,又重新把目光投向flush问题上,最终也确定了是这个问题。

首先,与PrintStream不同,PrintWriter不是遇到新行(ln,或n)就flush,而是在调用println,printf或者format方法被调用的时候flush的。然而这有一个前提,就是要开启自动flush的功能。这一设定是在PrintWriter的构造函数中的,autoFlush参数指定了构造的PrintWriter对象是否自动Flush:

PrintWriter(OutputStream out, boolean autoFlush)

PrintWriter(Writer out, boolean autoFlush)

以下构造函数构造的PrintWriter对象没有自动Flush属性:

PrintWriter(OutputStream out)

PrintWriter(Writer out)

PrintWriter(File file)

PrintWriter(File file, String csn)

PrintWriter(String fileName)

PrintWriter(String fileName, String csn)

Java SQL Statement初探

前几天说到新开始的Java项目,里面使用到了Java SQLite JDBC driver,今天继续来探讨一下Java中SQL数据库的使用。

应当注意到,在java当中,SQL语句的执行是以java.sql.Statement为载体的。我们先来看Statement的方法成员。有关java.sql.Statement的文档可以在Oracle找到。

Method 方法

executeQuery

ResultSet executeQuery(String sql)
                       throws SQLException

执行指定的SQL语句并返回一个结果集对象(ResultSet);

参数:

sql – 发送给数据库的sql语句,通常是静态的SQL SELECT语句;

返回:

一个包含查询结果的ResultSet对象,永远非空;

抛出:

SQLException – 如果数据库访问错误则抛出异常,比如说在已结束的Statement中调用这个方法或者SQL语句执行结果不是一个ResultSet。

executeUpdate

int executeUpdate(String sql)
                  throws SQLException

执行指定的SQL语句,比如INSERT,UPDATE或者DELETE语句,或者说是一个不产生结果的SQL语句,比如SQL DDL语句;

参数:

sql – 一组SQL Data Manipulation Language (DML)语句,比如INSERT,UPDATE或者DELETE;再或者说是一个不产生结果的SQL语句,比如SQL DDL语句;

返回:

以下可能:
(1)SQL Data Manipulation Language (DML)语句行数;
(2)如果SQL语句执行结果没有返回值则返回0;

抛出:

SQLException – 如果数据库访问错误则抛出异常,比如说在已结束的Statement中调用这个方法或者SQL语句执行结果产生了一个ResultSet。

close

void close()
           throws SQLException

立即释放Statement对象的数据库和JDBC资源而不是等待其自动关闭。通常来说在工作完成后立即释放资源是一个好的做法以避免耗尽数据库资源。
在一个一杯关闭的Statement对象上调用此方法不会有任何效果。

备注:

当一个Statement被关闭,其当前的结果集如果存在,则也会被关闭;

抛出:

SQLException – 如果数据库访问错误则抛出异常。

Java SQLite 初探

最近开始新的项目,初步规划使用Java,以及SQLite做CS架构的应用。目前用的是SQLite JDBC Driver 3.7.2。

使用的时候,首先引用

import java.sql.*

然后连接到数据库:

java.sql.Connection connection = java.sql.DriverManager.getConnection("jdbc:sqlite:sample.db");

执行SQL语句,准备查询字符串,以及执行查询:

java.sql.Statement statement = connection.createStatement();
statement.executeUpdate("drop table if exists sample");
statement.executeUpdate("create table sample(int_1 integer, str_1 string)");
statement.executeUpdate("insert into sample values(1, 'first')");
statement.executeUpdate("insert into sample values(2, 'second')");
java.sql.ResultSet rs = statement.executeQuery("select * from sample");

从结果集中取出内容:

while(rs.next())
{
    System.out.println("string = " + rs.getString("str_1"));
    System.out.println("integer = " + rs.getInt("int_1"));
}

到此为止上述代码完成了最基础的SQL语句的执行操作,SQLite数据库和java语言环境成功地连接起来了。

然而必须要说的是,这里使用的JDBC Driver尽管实现了上述操作,达到了在java环境中使用SQLite数据库的目标,但是数据库性能真的是令人堪忧。目前我们还没有进一步的需求使用更高性能的数据库,所以依然在使用JDBC Driver,但是如果日后对数据库的要求上来了,我估计在维持java和SQLite两个选项不变的前提下,是很需要把JDBC Driver换成相应的C Wrapper的。

站点迁移完成

今天完成了从旧站点fishinbox到新站点staryland.com的迁移工作。旧的fishinbox.tk站点依然存在,只是不会继续维护了。

新的站点依然使用cloudflare的CDN服务,国内访问速度不是很乐观,但是好在方便省心,激进的优化设置也许会有兼容性问题,不过就目前来看,在本站上运行状况良好。

此次迁移也标志着我正式开始记录日志了,思绪或者经验总是要与人分享的,记录下来宜人宜己。本站内容主要集中在编程(C++,C#,Java,PHP),数据库应用(SQL)等方面上,但日后会更加丰富。

成绩查询器失效说明

关于昨天下午发生的成绩查询器不稳定以及之后的不能查询成绩的说明。

自2012年初到现在大概有1年的时间了,很多人使用了我发布的成绩查询器,感谢大家的支持。经同学们的反馈,考虑到原1.0版本易用性以及安全性并不是特别理想,在考完后15号-16号期间完成了成绩查询器1.1的重编写与调试。

1.1版本有以下新的功能:

1、15号上午:URP系统以及查询窗口并列显示,且URP页面默认导向本学期成绩页面;用户可以方便的使用上方URP系统的参数来查询详细成绩组成以及暂存成绩的录入状态。

2、15号下午:加入了程序可用性验证,以减少程序潜在的不恰当使用的后果。

3、16号上午:一键查询当前登陆用户本学期所有详细成绩及状态

这里要说明一下,程序使用的是一个接口,对该接口教务系统开发者未正确处理,导致了接口公共空间可用性的存在。

16号增加的一键查询功能,可以使得用户机在短时间内(内网的话1000ms以内)产生对该接口大量的数据请求。程序测试过程中以及后来的小范围分发测试,很可能引起了教务服务器维护人员的注意,并且针对此做出修改(事实上修复这个缺陷应当是一个相当简单的事)。

所以很遗憾,该缺陷被修补后,所有我发布的成绩查询程序都不能够继续正常使用,不论是0.x测试版,1.0版还是1.1测试版。

目前有迹象表明可以使用另一个接口访问成绩数据,但是出于各种考虑不会发布相关查询软件。

再次感谢大家的支持。