<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>四号程序员</title>
	<atom:link href="http://www.coder4.com/feed" rel="self" type="application/rss+xml" />
	<link>http://www.coder4.com</link>
	<description>Keep It Simple And Stupid</description>
	<lastBuildDate>Thu, 23 Feb 2012 06:50:29 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>关于Windows XP下远程桌面连接Windows 7 Windows 2003</title>
		<link>http://www.coder4.com/archives/2935</link>
		<comments>http://www.coder4.com/archives/2935#comments</comments>
		<pubDate>Thu, 23 Feb 2012 06:50:29 +0000</pubDate>
		<dc:creator>coder4</dc:creator>
				<category><![CDATA[未分类]]></category>

		<guid isPermaLink="false">http://www.coder4.com/?p=2935</guid>
		<description><![CDATA[即使增加了“支持网络级别身份验证”也不好用的，请大家自行下载补丁：KB969084
直接升级客户端到7.0。。。。]]></description>
		<wfw:commentRss>http://www.coder4.com/archives/2935/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关于写Python 2和Python 3兼容的代码</title>
		<link>http://www.coder4.com/archives/2931</link>
		<comments>http://www.coder4.com/archives/2931#comments</comments>
		<pubDate>Tue, 21 Feb 2012 02:15:18 +0000</pubDate>
		<dc:creator>coder4</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[py3k]]></category>
		<category><![CDATA[兼容]]></category>

		<guid isPermaLink="false">http://www.coder4.com/?p=2931</guid>
		<description><![CDATA[有空看一下这个代码：

<a href="http://pypi.python.org/pypi/six/1.1.0">http://pypi.python.org/pypi/six/1.1.0</a>

算是除了2to3外的另一个选择吧。]]></description>
		<wfw:commentRss>http://www.coder4.com/archives/2931/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>一个Python写的Socks 5服务器</title>
		<link>http://www.coder4.com/archives/2929</link>
		<comments>http://www.coder4.com/archives/2929#comments</comments>
		<pubDate>Wed, 15 Feb 2012 09:23:52 +0000</pubDate>
		<dc:creator>coder4</dc:creator>
				<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.coder4.com/?p=2929</guid>
		<description><![CDATA[https://bitbucket.org/keli/furion

推荐下。]]></description>
		<wfw:commentRss>http://www.coder4.com/archives/2929/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python3使用setuptools</title>
		<link>http://www.coder4.com/archives/2926</link>
		<comments>http://www.coder4.com/archives/2926#comments</comments>
		<pubDate>Tue, 14 Feb 2012 09:52:32 +0000</pubDate>
		<dc:creator>coder4</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[distribute]]></category>
		<category><![CDATA[python3]]></category>
		<category><![CDATA[setuptools]]></category>

		<guid isPermaLink="false">http://www.coder4.com/?p=2926</guid>
		<description><![CDATA[旧版的setuptools已经不能用于Python3上了，国外有大神fork出了另一分支distribute，它可以支持Python3：
<pre class="brush: bash; gutter: true">#下载
wget http://pypi.python.org/packages/source/d/distribute/distribute-0.6.24.tar.gz

#解压缩 &#38;&#38; 安装
tar -xzvf ./distribute-0.6.24.tar.gz 
cd distribute-0.6.24/
python3 ./setup.py install</pre>
搞定。。

&#160;]]></description>
		<wfw:commentRss>http://www.coder4.com/archives/2926/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>大量数据取k个最大值并排序</title>
		<link>http://www.coder4.com/archives/2920</link>
		<comments>http://www.coder4.com/archives/2920#comments</comments>
		<pubDate>Tue, 14 Feb 2012 07:47:45 +0000</pubDate>
		<dc:creator>coder4</dc:creator>
				<category><![CDATA[C && C++]]></category>
		<category><![CDATA[算法&数据结构]]></category>
		<category><![CDATA[k最大]]></category>
		<category><![CDATA[算法]]></category>
		<category><![CDATA[面试]]></category>

		<guid isPermaLink="false">http://www.coder4.com/?p=2920</guid>
		<description><![CDATA[需求是这样的，我们都知道，在信息检索中，经常要取top-k(一共k，而不是第k)个得分最大的文档，并且从大到小排序。

而且文档规模很大，最少也要上千万。

话说这是一道很可以拿来面试的题啊。

我们不考虑Hadoop神马的，就说说单机怎么搞。

最傻的做法就是把1000万个都存储下来，然后sort，然后取min(k, vec.size())。

这样有两个缺点：
1、内存占用非常大，其实我们只要保留最大的1000个，但这样就要保存N个。在1000万的测试中，它要占用68M内存之多。
2、速度慢虽然是快速排序，但我们实际只要前1000个，后面那些排序都是无用功了。

于是靠谱的做法就是构建一个小顶堆：
(1)当堆中元素数量小于k时， 向堆中加入元素并调整堆
(2)当堆中元素数量大于等于k时 ，将堆顶（显然是当前最小的）和新元素比较：
(a)如果新元素小，丢弃之，我们只要top k 最大的。
(b) 如果新元素比堆顶大，把堆顶用新元素换掉，然后调整堆。

好了，理论是上面这个过程，我们一般就不要裸写堆了，用c++ stl的pop_heap/make_heap/push_heap搞定之。注意它没有调整堆单独的函数，而是第一次make_heap，之后用成对的pop_heap/push_heap来完成堆维护（这两个操作不会改变堆大小）。而堆是构建在vector基础上的。

细节是：上述默认都是构造大顶堆，从小到大排序等。于是我们要子构造一个反向排序函数。

好了，再重复一下堆：

小顶堆：堆顶始终是最小的元素，排序时把最小的换到末尾，类似选择排序的过程。这样拍出来的是从大到小。

大顶堆：排序之后从小到大。

比较一下性能(1kw个数据，值域0~1kw)：

算法/内存/时间：

(1)sort topk / 68MB / 11s
(2)heap / 3MB / 6s

内存优势非常明显。时间优势在这个规模可能还显示不出来，也可能是qsort的随机性能。

堆解决代码：
<pre class="brush: cpp; gutter: true">#include &#60;iostream&#62;
#include &#60;algorithm&#62;
#include &#60;vector&#62;
using namespace std;

//type use long
typedef long TYPE;

//反向比较器，将make_heap等函数转化为小顶堆
bool rcmp (const TYPE &#38;a,const TYPE &#38;b)
{
	return a&#62;b;
}

//An vector for global, would keep at most k elements
vector&#60;TYPE&#62; vec;
TYPE k;

//recv elemnts and keep top K(big), select top k
void recv_keep_top_k(TYPE elem) {
	if(vec.size()&#60;k) {
		vec.push_back(elem);
		if(vec.size()&#62;=k) {
			make_heap(vec.begin(), vec.end(), rcmp);
		}
	} else {
		// exceed k, need select

		//compare to smallest
		if(elem &#60; vec.front() ) {
			//small than heap&#039;s small, drop
			return;
		}

		//bigger than smallest in heap, keep and replace the small one
		pop_heap(vec.begin(), vec.end(), rcmp);
		vec.back() = elem;
		push_heap(vec.begin(), vec.end(), rcmp);
		return;
	}
}

int main () {

	k = 100;

	TYPE e;

	while(cin&#62;&#62;e) {
		recv_keep_top_k(e);
	}

	//sort from small to big
	//Each time, the smallest one was swap to tail
	if(vec.size()&#60; k) {
		make_heap(vec.begin(), vec.end(), rcmp);
	}
	sort_heap(vec.begin(),vec.end(), rcmp);

	cout &#60;&#60; &#34;Final top &#34; &#60;&#60; k &#60;&#60; endl;
	for (unsigned i=0; i&#60;vec.size(); i++) {
		cout &#60;&#60; vec[i] &#60;&#60; endl;
	}

	return 0;
}</pre>
对照组小白鼠（sort topK）：
<pre class="brush: cpp; gutter: true">#include &#60;iostream&#62;
#include &#60;algorithm&#62;
#include &#60;vector&#62;
using namespace std;

//type use long
typedef long TYPE;

bool rcmp (const TYPE &#38;a,const TYPE &#38;b)
{
	return a&#62;b;
}

//An vector for global, would keep at most k elements
vector&#60;TYPE&#62; vec;
TYPE k;

int main () {

	k = 100;

	TYPE e;

	while(cin&#62;&#62;e) {
		vec.push_back(e);
	}

	//sort from big to small
	sort(vec.begin(), vec.end(), rcmp);

	cout &#60;&#60; &#34;Final top &#34; &#60;&#60; k &#60;&#60; endl;
	for (unsigned i=0; i&#60;k &#38;&#38; i&#60;vec.size(); i++) {
		cout &#60;&#60; vec[i] &#60;&#60; endl;
	}

	return 0;
}</pre>
&#160;]]></description>
		<wfw:commentRss>http://www.coder4.com/archives/2920/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>这就是理论有余，实践不足么？</title>
		<link>http://www.coder4.com/archives/2916</link>
		<comments>http://www.coder4.com/archives/2916#comments</comments>
		<pubDate>Mon, 13 Feb 2012 15:17:40 +0000</pubDate>
		<dc:creator>coder4</dc:creator>
				<category><![CDATA[Java && J2EE]]></category>
		<category><![CDATA[多线程]]></category>

		<guid isPermaLink="false">http://www.coder4.com/?p=2916</guid>
		<description><![CDATA[今天看到一个问题，两个线程，轮流交替输出1,2,1,2。。。

看似很简单是吧，就是条件控制么，果断最简单的wait和notify，但是一致报IllegalMonitorStateException，各种囧啊，各种试。最后发现是obj.wait()和obj.notify()必须放在synchronized块内。。之前真的真的从来没注意过这个细节。。。
<pre class="brush: java; gutter: true">public class TestPrint {

	public static void main(String[] args) throws Exception {

		final Object obj = new Object();

		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					while (true) {
						synchronized (obj) {
							obj.notifyAll();
							obj.wait();
							System.out.println(1);
						}
					}

				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});

		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					while (true) {
						synchronized (obj) {
							obj.notifyAll();
							obj.wait();
							System.out.println(2);
						}
					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
		t1.start();
		t2.start();
	};
}</pre>]]></description>
		<wfw:commentRss>http://www.coder4.com/archives/2916/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java核心技术卷II(第8版) – 读书笔记 – 第4章</title>
		<link>http://www.coder4.com/archives/2906</link>
		<comments>http://www.coder4.com/archives/2906#comments</comments>
		<pubDate>Sun, 12 Feb 2012 09:07:32 +0000</pubDate>
		<dc:creator>coder4</dc:creator>
				<category><![CDATA[Java && J2EE]]></category>
		<category><![CDATA[Java核心技术]]></category>
		<category><![CDATA[JDBC]]></category>
		<category><![CDATA[NoSQL && RDMBS]]></category>
		<category><![CDATA[卷2]]></category>
		<category><![CDATA[核心技术]]></category>
		<category><![CDATA[第3章]]></category>
		<category><![CDATA[读书笔记]]></category>

		<guid isPermaLink="false">http://www.coder4.com/?p=2906</guid>
		<description><![CDATA[本章主要记录Java操作数据库

1、JDBC是Java操作数据库的接口，现在的版本已经是JDBC 4了。

2、JDBC的设计理念就是提供一套基本统一，纯Java的API数据库访问接口。JDBC实际是驱动管理器，各个厂家提供JDBC规范的驱动，注册到管理器中。这样，开发者使用JDBC API，而数据库厂商使用JDBC驱动API。

3、JDBC驱动的分类：
(1)JDBC/ODBC桥：将JDBC翻译成ODBC，然后实际调用ODBC来完成数据库操作。
(2)JDBC+本地代码：用JNI调用其他语言的驱动，封装成JDBC。
(3)纯Java客户端，使用协议无关的请求发送给服务器。
(4)纯Java客户端，JDBC客户端直接翻译成特定的C/S请求，发到服务器端。

4、JDBC实现了一个很好的目标：
(1)程序员使用几乎一致的JDBC API操作各种类型的数据库
(2)厂商自己维护JDBC驱动。

5、传统的Java数据库系统：

Client(JDBC) -&#62; 数据库服务器

现在一半都会用三层分离：客户端 -&#62; 中间件 -&#62; 数据库

这样的话，JDBC主要运行在中间件这层，而客户端与中间件可以用HTTP、或者RPC、RMI等完成调用。

6、在关系模型中，我们将数据分配到多个表中，使得不会有冗余信息的出现，以防止更新时出现不一致的问题。

7、一些SQL语句

查询：
<pre class="brush: sql; gutter: true">select * from books

select ISBN, price, title from books

select title from books where price &#60;= 10.00

select title from books where id &#60;&#62; 1  #注意&#60;&#62;才是不等于，!=是不标准的！

select title from books where id = 1  #注意=而不是==</pre>
注意上述查询中，&#60;&#62;才是不等于，而=而不是==表示等于。

模糊查询用like，%表示0~N个字符，下划线_表示单个字符。
<pre class="brush: sql; gutter: true">select title from books where title like &#039;%n_x%&#039;  #可以匹配标题linux或者unix

select * from books, publishers where books.publisher_id = publisher.publisher_id</pre>
注意上面的交叉表查询，实际是迪卡尔乘积的子集，它只返回有意义的并表（ID一致）。

更新或者删除操作：
<pre class="brush: sql; gutter: true">update books set price = price - 5.00 where title like &#039;%c++%&#039;  #全部的c++书减价5块

delete from books where title like &#039;%c++%&#039;  #删除所有c++的书</pre>
插入数据：
<pre class="brush: sql; gutter: true">insert into books values(&#039;A guide to java&#039;, &#039;0-33-4-22-5555&#039;, 0, 45.5)  #必须逐项对应books的每个字段</pre>
创建表：
<pre class="brush: sql; gutter: true">create table books
(
  title CHAR(50),
  ISBN CHAR(50),
  id int(10),
  price decimal(10,2)
)</pre>
8、除了选择MySQL、Oracle等之外，我们其实可以用Apache Derby，它已经成为了JDK6的一部分。

9、

&#160;

&#160;

&#160;

&#160;

&#160;

&#160;

&#160;

&#160;

&#160;

&#160;

&#160;

&#160;

&#160;

&#160;

&#160;

&#160;]]></description>
		<wfw:commentRss>http://www.coder4.com/archives/2906/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java核心技术卷II(第8版) – 读书笔记 – 第3章</title>
		<link>http://www.coder4.com/archives/2898</link>
		<comments>http://www.coder4.com/archives/2898#comments</comments>
		<pubDate>Tue, 07 Feb 2012 14:23:37 +0000</pubDate>
		<dc:creator>coder4</dc:creator>
				<category><![CDATA[Java && J2EE]]></category>
		<category><![CDATA[Java核心技术]]></category>
		<category><![CDATA[卷2]]></category>
		<category><![CDATA[核心技术]]></category>
		<category><![CDATA[第3章]]></category>
		<category><![CDATA[网络编程]]></category>
		<category><![CDATA[读书笔记]]></category>

		<guid isPermaLink="false">http://www.coder4.com/?p=2898</guid>
		<description><![CDATA[本章是重头戏：网络编程！

1、首先测试一下daytime服务：
<pre class="brush: bash; gutter: true">telnet time.nist.gov 13

Trying 192.43.244.18...
Connected to ntp.glb.nist.gov.
Escape character is &#039;^]&#039;.

55965 12-02-08 12:34:39 00 0 0 612.3 UTC(NIST) *
Connection closed by foreign host.</pre>
这个过程中，DNS将ntp.glb.nist.gov解析为IP地址，然后TCP连接端口13，接下来反复读取、交换数据，直到连接关闭。

2、用基本的Java的Socket模拟上述过程：
<pre class="brush: java; gutter: true">import java.io.*;
import java.net.*;
import java.util.*;

public class SocketTest {
    public static void main(String [] args) {
        Socket socket = null;
        try {
            socket = new Socket(&#34;time.nist.gov&#34;, 13);

            InputStream in = socket.getInputStream();
            Scanner scan = new Scanner(in);
            while(scan.hasNextLine()) {
                String line = scan.nextLine();
                System.out.println(line);
            }
        } catch(Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if(socket!=null) {
                    socket.close();
                }
            } catch(Exception e1) {
            }
        }   

    }
}</pre>
3、上述代码，首先构造Socket，创建一个套接字。
如果失败会抛出各种异常，如UnknownHostException(解析错误)或者IOException(其他错误)。
然后通过getInputStream获取InputStream，这是从远程到本机的“数据管道 ”。

4、上述例子很简单，因为只有服务器主动向客户发送数据，之后就关闭了。一般的通信，是需要客户和服务器双方交互并进行复杂的协议规定。

5、在Socket建立起连接之后，InputStream的read可能需要一定的等待时间才能得到数据。对于有的应用，这是不可接受的，或者说这个的等待时间需要有上限，我们可以设置这个timeout时间：
<pre class="brush: java; gutter: true">socket.setSoTimeout(2*1000);</pre>
注意单位是ms，而且这个只对read()操作有效。

6、对于connect()（在Java对应的是构造Socket的过程），那么需要单独的使用connect来实现：
<pre class="brush: java; gutter: true">Socket socket  = new Socket();
socket.connect(xxx, 2*1000);</pre>
7、IPV4地址为4个字节，IPV6地址为16个字节。Java支持V4和V6地址。解析域名到IP地址：
<pre class="brush: java; gutter: true">import java.net.*;

public class DNSTest {
    public static void main(String [] args) throws Exception {
        InetAddress addrs[] = InetAddress.getAllByName(&#34;www.google.com&#34;);
        for(int i=0; i&#60;addrs.length; i++) {
            System.out.println(addrs[i].getHostAddress());
        }
    }
}</pre>
一些网站都会在一个域名上设置多个IP地址，以达到负载均衡，上面这个getAllByName就是可以取到全部的IP地址，比如google的有如下结果：
<pre class="brush: bash; gutter: true">74.125.71.106
74.125.71.147
74.125.71.99
74.125.71.103
74.125.71.104
74.125.71.105</pre>
8、如果想要获得本机IP地址，可以用：
<pre class="brush: java; gutter: true">InetAddress addr = InetAddress.getLocalHost();</pre>
9、下面是创建一个最简单的网络服务器端的步骤：
(1)建立ServerSocket s = new ServerSocket(8888)
(2) Socket incoming = s.accept();
(3) income就是客户了，在此基础上进行交互，执行相应的逻辑，使用input/outputstream。
(4)关闭income的socket。

上面的逻辑部分，我们使用最简单的Echo，即客户发送什么，我们回显什么。
<pre class="brush: java; gutter: true">import java.util.*;
import java.net.*;
import java.io.*;

public class EchoServer {
    public static void main(String [] args) {
        try {
            ServerSocket server = new ServerSocket(8888);

            byte [] buf = new byte[1024];
            int len = 0;
            while(true) {
                Socket client = server.accept(); // accept client
                try {
                    InputStream in = client.getInputStream();
                    OutputStream out = client.getOutputStream();

                    while((len = in.read(buf, 0, 1024))!=-1) {
                        out.write(buf, 0, len);
                    }
                } catch(Exception e1) {
                    e1.printStackTrace();
                } finally {
                    if(client!=null) {
                        client.close();
                    }
                }
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}</pre>
我这里直接用的最裸的inputstream/outputstream，直接read/write了，没有用PrintWriter神马的。

10、上面这个Server有个问题，多个client同时请求时候，后面的会被hold住（挂起）。。。肿么办？最简单的是多线程搞起，一个新client给开一个新线程处理：

但是这种的效率不会特别高，建议尽量用nio的一些特性。
<pre class="brush: java; gutter: true">import java.util.*;
import java.net.*;
import java.io.*;

class ThreadEchoHandler implements Runnable {

	public ThreadEchoHandler(Socket socket) {
		this.socket = socket;
	}

	public void run() {
		byte [] buf = new byte[1024];
		int len = 0;
		try {
			InputStream in = socket.getInputStream();
			OutputStream out = socket.getOutputStream();
			while((len = in.read(buf, 0, 1024))!=-1) {
				out.write(buf, 0, len);
			}
		} catch(Exception e1) {
			e1.printStackTrace();
		} finally {
			try {
				socket.close();
			} catch(Exception e) {
			}
		}
	}

	private Socket socket;
}

public class ThreadEchoServer {
	public static void main(String [] args) {
		try {
			ServerSocket server = new ServerSocket(8888);

			while(true) {
				Socket client = server.accept(); // accept client
				Thread t = new Thread(new ThreadEchoHandler(client)); //new thread
				t.start();
			}
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
}</pre>
11、半关闭：套接字连接的一端终止其输出，同时仍旧可以接受来自另外一端的数据。应用场景，例如：我们要向服务器端发送数据，但不知道一共要传输多少。可以一直发送，发送后关闭写通道（但要保持读通道开启）。此时服务器端将会知道这一事件，做出对应处理。

12、半关闭适用于“一站式”协议，如HTTP，客户发送一个请求，然后服务器也回送一个响应。这时用半关闭很好：
<pre class="brush: java; gutter: true">Socket socket = new Socket(&#34;127.0.0.1&#34;, 8080);
OutputStream output = socket.getOutputStream();
while(true)
{
    out.write(...);
}
socket.shutdownOutput();   //半关闭！
while(..)
{
    in.read(...);
}
socket.close();</pre>
13、在交互式网络协议中，想实现“如果某个连接长期没有响应，变中止它”。这种需要用nio的SocketChannel来辅助实现。
<pre class="brush: java; gutter: true">SocketChannel channel = SocketChannel.open(new InetSocketAddress(host, port));
OutputStrem out = Channels.newOutputStream(channel);</pre>
然后在需要中断的时候：

thread.interrupt()就可以了，对应的OutputStream会退出，因为这个创建出来的是interruptible I/O。

14、发送E-Mail的例子。

SMTP协议发送E-Mail实际是客户端，相当于Foxmail等。

协议：

HELO sending host
MAIL FROM: &#60;Sender email&#62;
RCPT TO: &#60;Recp email&#62;
DATA
xxxx
xxxx
.
QUIT

每一行都是\r\n换行。

没什么特别的。。JDK已经有JavaMail提供了很完善的功能。

15、如果要进行更高层次的开发，如HTTP，可以考虑URL类。

和它长的很像的还有一个URI，这主要是用于记录地址的，比如：

mailto:xxx@xx.com、http://www.xxx.com

URI的格式是规定好的：

[schema]schemaSpcificPart[#fragmant]

可以使用“相对化”处理层次的URI。

16、如果要抓起Web页面，可以直接用URLConnection。

(1)URL url = ...
(2)conn = url.OpenConnection()
(3)conn.setXXX(UseCache/Modify/ReadTimeout)等HTTP请求的属性。
(4)conn.connect()
(5)连接之后，可以getContentType/getContentLength/...查询Response中HTTP的标准字段，也可以getHeaderFieldKey和getHeaderField来枚举所有的头。
(6)读、写用getInputStream和getOutputStream搞定。

下面是一个基本的例子，抓取网页，打印response中的字段。
<pre class="brush: java; gutter: true">import java.net.*;
import java.io.*;
import java.util.*;

public class URLTest {
    public static void main(String [] args) throws Exception {
        URL url = new URL(&#34;http://www.ict.ac.cn&#34;);
        URLConnection conn = url.openConnection();
        InputStream in = conn.getInputStream();
        StringBuilder sb = new StringBuilder();
        byte [] buf = new byte[1024];
        int len;
        while(( len = in.read(buf, 0, 1024))!=-1) {
            sb.append(new String(buf, 0, len));
        }
        System.out.println(sb.toString());
        Map&#60;String,List&#60;String&#62;&#62; header_map = conn.getHeaderFields();
        for(String key:header_map.keySet()) {
            System.out.println(key+&#34; = &#34;+header_map.get(key));
        }
    }
}</pre>
17、如果要发送表单神马的必须conn.setDoInput(true) 。

18、定制请求头，conn.setRequestProperty()：
<pre class="brush: java; gutter: true">public void setRequestProperty(String key,
                      String value);</pre>
19、下面是一个向一个支持POST的页面发送POST的例子。
<pre class="brush: java; gutter: true">import java.net.*;
import java.io.*;
import java.util.*;

public class PostTest {
    public static void main(String [] args) throws Exception {
        //POST DATA key &#38; value
        URL url = new URL(&#34;http://www.coder4.com/post.php&#34;);
        URLConnection conn = url.openConnection();
        conn.setDoOutput(true);
        PrintWriter writer = new PrintWriter(conn.getOutputStream());
        writer.print(&#34;post_key=&#34;);
        writer.println(URLEncoder.encode(&#34;这是一段POST数据&#34;, &#34;UTF-8&#34;));
        writer.close();

        //Input
        InputStream in = conn.getInputStream();
        StringBuilder sb = new StringBuilder();
        byte [] buf = new byte[1024];
        int len;
        while(( len = in.read(buf, 0, 1024))!=-1) {
            sb.append(new String(buf, 0, len));
        }
        System.out.println(sb.toString());
        Map&#60;String,List&#60;String&#62;&#62; header_map = conn.getHeaderFields();
        for(String key:header_map.keySet()) {
            System.out.println(key+&#34; = &#34;+header_map.get(key));
        }
        in.close();
    }
}</pre>
本章完毕。

（Java核心技术对于网络这部分不给力啊。。UDP、NIO都没写，改天找找资料自己补上）

&#160;

&#160;]]></description>
		<wfw:commentRss>http://www.coder4.com/archives/2898/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java核心技术卷II(第8版) – 读书笔记 – 第2章</title>
		<link>http://www.coder4.com/archives/2890</link>
		<comments>http://www.coder4.com/archives/2890#comments</comments>
		<pubDate>Mon, 06 Feb 2012 13:11:53 +0000</pubDate>
		<dc:creator>coder4</dc:creator>
				<category><![CDATA[Java && J2EE]]></category>
		<category><![CDATA[Java核心技术]]></category>
		<category><![CDATA[XML]]></category>
		<category><![CDATA[卷2]]></category>
		<category><![CDATA[核心技术]]></category>
		<category><![CDATA[第2章]]></category>
		<category><![CDATA[读书笔记]]></category>

		<guid isPermaLink="false">http://www.coder4.com/?p=2890</guid>
		<description><![CDATA[本章主要介绍Java与XML。

1、XML非常适合表示复杂的、结构化数据。

2、XML与HTML有所差异，XML更严格，如：区分大小写、必须结束标签、属性必须有值。

3、XML以文档头开始，如：
<pre class="brush: java; gutter: true">&#60;?xml version=&#34;1.0&#34; encoding=&#34;utf-8&#34;?&#62;</pre>
4、然后包含若干元素和子元素。
<pre class="brush: java; gutter: true">&#60;configuration&#62;
  &#60;title&#62;&#60;/title&#62;
  ......
&#60;/configuration&#62;</pre>
5、如果能使用元素，就尽量不要使用属性，如：
<pre class="brush: xml; gutter: true">&#60;font&#62;
    &#60;family&#62;宋体&#60;/family&#62;
    &#60;size&#62;14&#60;/size&#62;
&#60;/font&#62;</pre>
要好于：
<pre class="brush: xml; gutter: true">&#60;font size=&#34;14&#34; family=&#34;宋体&#34;&#62;
&#60;/font&#62;</pre>
毕竟属性在解析时候非常麻烦。

6、除了元素、文本之外，还有一些特殊的片段：
(1)字符引用，如&#38;#十进制，&#38;#X十六进制
(2)实体引用，如&#38;lt; &#38;gt; &#38;amp; &#38;quot; &#38;apos;
(3)CDATA引用部分，在这之中可以自由的使用&#38;等上述特殊符号：
&#60;![CDATA[ &#60; &#38; &#62; 都可用 ]]&#62;，但是这部分内不能包含]]&#62;，要特别注意。
(4)处理命令，&#60;?xml 等
(5)注释：&#60;!-- 注释内容 --&#62;

7、解析XML有两种基本方式：
(1) 树状：将XML完全转化成树状结构，又叫DOM（Document Object Model）
(2)流解析：读入XML文档时生成对应的事件，流装，有的叫做SAX（Simple API for XML）。。。好冷啊。。。

8、DOM解析器的接口居然已经被W3C标准化了。。太神奇了，看来XML应用真广泛。。我第一次听说具体某个接口实现被标准化的。。。JDK自带的org.w3c.dom就是这种标准化的结果（SUN提供实现）。而我们使用的其他第三方，也基本遵循这样的接口标准。

9、使用Java自带的传统Parser（DOM解析器）解析文档：
<pre class="brush: java; gutter: true">//构造DocumentBuilderFactory实例
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//构造DocumentBuilder实例
DocumentBuilder builder = factory.newDocumentBuilder();
//用DocumentBuilder解析文档
Document doc = builder.parse(&#34;./test.xml&#34;);</pre>
10、Document由若干个Element(实际实现了Node)组成，父doc.getElement()将返回root结点。
获取孩子：getChildNodes()，但它会包含文字、结点等，如要用instanceof Element进行判断。
获取文字：getData()获取文本。
获取属性：getAttributes()

下面的例子演示了如何遍历孩子Node，判断类型（Element/Text/Attr） ，并打印特有的属性：
<pre class="brush: java; gutter: true">import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.*;
import java.io.*;

public class XMLTest {
    public static void main(String [] args) throws
        Exception {
            DocumentBuilderFactory factory =
                DocumentBuilderFactory.newInstance();
            DocumentBuilder builder =
                factory.newDocumentBuilder();
            Document doc = builder.parse(&#34;./sitemap.xml&#34;);

            //Get root element
            Element root = doc.getDocumentElement();
            //Get all children
            NodeList nodes =  root.getChildNodes();
            for(int i = 0; i &#60; nodes.getLength(); i++) {
                Node node = nodes.item(i);
                if(node instanceof Element) {
                    System.out.println(&#34;Element &#34;+node.getNodeName());
                    NamedNodeMap attr_map = node.getAttributes();
                    for(int j=0;j&#60;attr_map.getLength();j++) {
                        Node node_attr = attr_map.item(j);
                        if(node_attr instanceof Attr) {
                            System.out.println(((Attr)node_attr).getName() + &#34; &#34; + ((Attr)node_attr).getValue());
                        }
                    }
                } else if (node instanceof Text) {
                    System.out.println(&#34;Text &#34;+node.getNodeName());
                    System.out.println(((Text)node).getWholeText().trim());
                    System.out.println();
                } else {
                    System.out.println(node.getClass());
                }
            }
        }
}</pre>
11、由于XML是自解释结构，非常灵活。我们在解析、使用一个XML文档之前，并不知道它们是否是按照我们预想的结构组织的。于是，DTD或者Schema通过预先定义的文档结构方式，来<strong><span style="color: #ff0000;">验证</span></strong>一个xml是否符合自己预期的<strong><span style="color: #ff0000;">格式</span></strong>。

12、XML Schema比DTD的功能更为强大，较新的xml规范一般都采用XML Schema。

13、通常，把DTD定义单独做为.dtd文件，放在别的网站/URL上，然后从xml中引用：
<pre class="brush: xml; gutter: true">&#60;?xml version=&#34;1.0&#34; ?&#62;
&#60;!DOCTYPE configuration SYSTEM &#34;http://www.xxx.com/config.dtd&#34;</pre>
14、关于DTD规则不在描述了，如果确定一个xml是符合你指定的dtd，那么访问xml就可以很简单：

直接if(elem.getTag().equals("name")){....}

这样的处理就可以了。

设置解析器：

setEntityResolver(EntityResolver er)

一般需要再设置错误处理回调：

setErrorHandler(ErrorHandler eh)

15、如果需要只访问XML中的某一部分，那么用SAX有点大炮打蚊子了。。我们可以用XPath。例如下面的xml代码：
<pre class="brush: xml; gutter: true">&#60;configuration&#62;
    &#60;database&#62;
        &#60;user&#62;user&#60;/user&#62;
        &#60;pass&#62;123456&#60;/pass&#62;
    &#60;/database&#62;
&#60;/configuration&#62;</pre>
我们其实可以直接访问：/configuration/database/user来获取用户名：

而传统SAX要获得N个Element再判断神马的。

其他一些XPath语法：

/gridbag/row -&#62;可能是获得一组结点
/gridbag/row[1]  -&#62; 选定第一个row元素(下标从1开始)
@表示属性：
/gridbag/row[1]/cell[1]/@anchor

16、JDK5之后支持XPath了：javax.xml.xpath.XPathFactory

下面的例子演示了用XPath分别读取结点、数组、属性等。

evaluate的最后一个常量见javax.xml.xpath.XPathConstants。

如果是要一堆数组，直接NODESET，然后就被映射为NodeList了，麻烦写for就没写。
<pre class="brush: java; gutter: true">import javax.xml.parsers.*;
import javax.xml.xpath.*;
import org.w3c.dom.*;
import org.xml.sax.*;
import java.io.*;

public class TestXPath {
    public static void main(String [] args) throws Exception {
        //doc
        DocumentBuilderFactory factory =
            DocumentBuilderFactory.newInstance();
        DocumentBuilder builder =
            factory.newDocumentBuilder();
        Document doc = builder.parse(&#34;./sitemap.xml&#34;);
        //Xpath
        XPathFactory xpath_factory = XPathFactory.newInstance();
        XPath path = xpath_factory.newXPath();

        //XPath visit as Text
        String text = path.evaluate(&#34;/urlset/url[1]/loc&#34;, doc);
        System.out.println(text);

        //XPath visit as Node
        Node node = (Node)path.evaluate(&#34;/urlset/url[1]&#34;, doc, XPathConstants.NODE);
        System.out.println(node.getNodeName());

        //XPath visit as Number(as double)
        Double num = (Double)path.evaluate(&#34;/urlset/url[1]/priority&#34;, doc, XPathConstants.NUMBER);
        System.out.println(num);

    }
}</pre>
17、Java自带的xml解析器也支持命名空间，形如：
<pre class="brush: xml; gutter: true">&#60;xsd:schema xmlns:xsd=&#34;http://www.w3.org/2001/XMLSchema&#34;&#62;
......
&#60;/xsd:schema&#62;</pre>
对应的API中可以获得LocalName和URL空间：

Node.getLocalName()

Node.getNamespaceURI()

也可以获取工厂是否支持URL空间

DocumentBuilderFactory.isNamespaceAware()/SetNamespaceAware()

18、传统的DOM解析器试图将XML文件映射成树状结构。这对大的、复杂的XML是致命的。比较先进的方法是流解析器(streaming parser)，通过回调函数进行处理。

19、我们前面使用的都是传统Parser（默认的DocumentFactory），Java还提供SAX，用于流状解析XML文件，它更适用于大文件。

一个 SAXParser将在解析的过程中回调ContentHandler，后者需要自己实现，主要方法有：

startElement和endElement：在遇到起始、终止标签时使用。
characters：每当遇到字符数据时调用
startDocument和endDocument分别在文档开始和结束时各调用一次。

一般，我们可以直接使用DefaultHandler，它对上述方法都实现了空方法。我们需要在哪些地方做处理，直接覆盖对应的方法就可以了。

一个用SAXParser和startElement来打印所有结点的href属性的例子如下：

其实SAXParser真的很强大的……
<pre class="brush: java; gutter: true">import org.xml.sax.helpers.*;
import javax.xml.parsers.*;
import org.xml.sax.*;

public class SAXTest {
    public static void main(String [] args) throws Exception {
        //SAXParser
        SAXParserFactory sax_fac = SAXParserFactory.newInstance();
        SAXParser sax_parser = sax_fac.newSAXParser();

        //Handler
        DefaultHandler handler = new DefaultHandler()
        {
            public void startElement(String uri, String localName, String qName, Attributes attributes) {
                for(int i = 0; i &#60; attributes.getLength(); i++) {
                    String name = attributes.getLocalName(i);
                    if(name.equals(&#34;href&#34;)) {
                        String value = attributes.getValue(i);
                        System.out.println(value);
                    }
                }
            }
        };  

        //SAXParser
        sax_parser.parse(&#34;./sitemap.xml&#34;, handler);
    }
}</pre>
20、如果说SAX的事件处理是Push的（有事件来的时候自动回调预先定义的函数）。那么JDK6新提供的StAX就是Pull的。你需要自己去轮询事件：

StAX的名字是：XMLStreamReader

话说我没感觉比SAX简单。。。
<pre class="brush: java; gutter: true">import org.xml.sax.helpers.*;
import javax.xml.parsers.*;
import javax.xml.stream.*;
import org.xml.sax.*;
import java.io.*;

public class StAXTest {
    public static void main(String [] args) throws Exception {
        //StAXParser
        XMLInputFactory stax_fac = XMLInputFactory.newInstance();
        XMLStreamReader parser = stax_fac.createXMLStreamReader(new FileReader(&#34;./sitemap.xml&#34;));

        //Use reader to pull all event
        while(parser.hasNext()) {
            int event = parser.next();
            if(event==XMLStreamConstants.START_ELEMENT) {
                int attr_cnt = parser.getAttributeCount();
                if(attr_cnt!=0) {
                    for(int i=0;i&#60;attr_cnt; i++) {
                        String attr_name = parser.getAttributeLocalName(i);
                        if(attr_name.equals(&#34;href&#34;)) {
                            System.out.println(parser.getAttributeValue(i));
                        }
                    }
                }
            }
        }   

    }
}</pre>
21、 前面一直在研究如何解析(读取XML)，现在开始研究如何生成XML(生成XML)。

22、使用DOM树那个传统接口，可以一步一步地构造DOM树。但是奇怪的是……不支持输出到流。。。
<pre class="brush: java; gutter: true">//创建子结点
Document doc = builder.newDocument();
Element rootElement = doc.createElement(&#34;root&#34;);
doc.appendChild(rootElement);

//添加Text
Text textNode = doc.createTextNode(&#34;I&#039;m text string.&#34;);
rootElement.appendChild(textNode);

//设置属性
rootElement.setAttribute(name, value);</pre>
23、上面的方式需要用很恶心的方式才能输出出来。。。所以此时可以考虑切换到其他开源XML解析了。

24、如果一定要用JDK原生的搞定，可以用StAX，用XMLStreamWriter.writeXXX函数：

writeStartDocument()
writeEndDocument()
writeStartElement()
writeEndElement()
writeAttribute()
writeCharacters()

下面的，生成XML文档：
<pre class="brush: java; gutter: true">import org.xml.sax.helpers.*;
import javax.xml.parsers.*;
import javax.xml.stream.*;
import org.xml.sax.*;
import java.io.*;

public class WriteXMLTest {
    public static void main(String [] args) throws Exception {
        //StAXParser
        XMLOutputFactory stax_fac = XMLOutputFactory.newInstance();
        XMLStreamWriter writer = stax_fac.createXMLStreamWriter(new FileWriter(&#34;./temp.xml&#34;));

        //Make document
        writer.writeStartDocument();
        //make root node
        writer.writeStartElement(&#34;root&#34;);
        //make node1 node and attribute
        writer.writeStartElement(&#34;node1&#34;);
        writer.writeAttribute(&#34;attr&#34;, &#34;attr_value&#34;);
        writer.writeEndElement();
        writer.writeEndElement();
        writer.writeEndDocument();
        //Flush to disk
        writer.close();
    }   
}</pre>
25、XSL转换(XSLT)：可以将XML转化成其他HTML、文本等。需要提供XSLT样式表。

26、Java中用TransformFactory+StreamSource可以完成XSLT转化。这货已经非常不主流了。。所以不写代码了。

本章完毕。

&#160;

&#160;

&#160;]]></description>
		<wfw:commentRss>http://www.coder4.com/archives/2890/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关于Java nio的一些资料</title>
		<link>http://www.coder4.com/archives/2860</link>
		<comments>http://www.coder4.com/archives/2860#comments</comments>
		<pubDate>Fri, 03 Feb 2012 06:23:58 +0000</pubDate>
		<dc:creator>coder4</dc:creator>
				<category><![CDATA[Java && J2EE]]></category>
		<category><![CDATA[nio]]></category>

		<guid isPermaLink="false">http://www.coder4.com/?p=2860</guid>
		<description><![CDATA[<a href="http://rox-xmlrpc.sourceforge.net/niotut/">http://rox-xmlrpc.sourceforge.net/niotut/</a>

<a href="http://tutorials.jenkov.com/java-nio/index.html">http://tutorials.jenkov.com/java-nio/index.html</a>

<a href="http://www.cs.brown.edu/courses/cs161/papers/j-nio-ltr.pdf">http://www.cs.brown.edu/courses/cs161/papers/j-nio-ltr.pdf</a>

&#160;]]></description>
		<wfw:commentRss>http://www.coder4.com/archives/2860/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

