最近在看,How Tomcat Works,反正感觉上就是叼叼的,看完第一章就想自己写个服务器出来了,大概原理应该弄得差不多了:客户端与服务器端通讯,不管是什么B/S,C/S啊,都是在通讯,通讯就是交换信息,就像是两个人交流,你给我发消息,我给你发消息。但是因为这两个人有可能是不同地区的人,他们将不同的语言,所以制定了一系列的交流的规则,首先说什么,然后说什么,不能说什么……这就是协议,web层通讯采用的最多的就是HTTP协议,协议向下封装,什么底层透明性那些就不说了,,,反正到最后在电线中传播的都是0101010101这样的字符串了,物理上使用高低电压表示的,但是我就不知道在光缆、空气等传输介质中是怎么表示的呢,但是最后客户端、服务器端接收到的信息都是010101,就是所谓的字节流(bit),然后将这些字节流按编码(GBK、UTF-8)规则翻译成人能够轻松识别的语言,就这样了。接着我的问题就来了:
问题描述:我在一个java文件中写了中文字符,并将这些字符输出到客户端,但是客户端总是显示不出来。
问题探索:我写的java文件是会保存到物理磁盘的,这样保存时会有一个编码选择,但是我的客户端访问这个程序时是访问已编译后的字节码文件啊,就是那个.class文件。我先讲java文件以UTF-8编码格式保存,然后访问那个.class文件,看客户端的输出,然后将java文件以GBK编码格式保存,再试,结果就是设置浏览器的编码为GB2312(GBK的简化版)时,我java代码中的中文能正常显示在浏览器中,浏览器的编码设置为UTF-8时,网页显示乱码,我输出的方式是直接从socket上获取的OutputStream对象,这就是字节流,就是直接将010101输出到了客户端,由客户决定采用哪种编码去显示。
我输出的中文:
<span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;"> @Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println("servlet service开始执行.");
PrintWriter printWriter=res.getWriter();
printWriter.println("你好,小王子~");
printWriter.print("你从哪里来的呀~");
System.out.println("haha~");
}</span></span></span>
<span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;"> @Override
public PrintWriter getWriter() throws IOException {
printWriter=new PrintWriter(output,true);
return printWriter;
}</span></span></span>
output是从socket上直接获取的:
<span style="font-size:14px;"><span style="font-size:14px;">OutputStream output=socket.getOutputStream();</span></span>
哎呀,写着写着,又发现问题了,就是PrintWriter不知道有没有对中文进行编码?
反正我都试了,懒得细说了,直接用output输出,也是一样的,
最后的结论就是:java文件编译生成得.class文件是无所谓编码的,就是与java文件保存的编码格式无关。。。。但我还是不知道这是怎么实现的?
……以上结论无效,,彻底混乱啦!
-------------------------------------------------------------
更新:
结论:只与获取到socket对象的所在代码文件的编码有关,就是在该代码存在的文件中,该文件以什么格式保存,则输出到客户端的格式就是什么样的。
该测试的简化代码如下:
<span style="font-size:14px;"><span style="font-size:14px;">package test;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandler;
import java.net.UnknownHostException;
import javax.servlet.Servlet;
public class HttpServer {
public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot";
private boolean shutdown = false;
public static void main(String[] args) {
HttpServer server = new HttpServer();
System.out.println(WEB_ROOT+"\n");
server.await();
}
private void await() {
ServerSocket serverSocket = null;
int port = 8088;
try {
serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
while (!shutdown) {
Socket socket = null;
OutputStream output = null;
Response response=null;
try {
socket = serverSocket.accept();
output=socket.getOutputStream();
response=new Response(output);
output.write("小王子11".getBytes());
URL[] urls=new URL[1];
URLStreamHandler urlStreamHandler = null;
File classPath = new File("G:\\HowTomcatWorks\\JavaWebServer\\webroot");
String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString();
System.out.println(repository);
urls[0] = new URL(null, repository, urlStreamHandler);
URLClassLoader loader =new URLClassLoader(urls);
Class myClass = null;
try {
myClass = loader.loadClass("TestServlet");
Servlet servlet = (Servlet) myClass.newInstance();
servlet.service( null, response);
} catch (Exception e) {
e.printStackTrace();
}
socket.close();
} catch (IOException e) {
e.printStackTrace();
continue;
}
}
}
}
</span></span>
然后我又发现了一个问题:本来我是想加载指定目录下的class文件的,这里我想加载:"G:\HowTomcatWorks\JavaWebServer\webroot\TestServlet.class"这个类文件,可是我将这儿的文件删了,照样可以运行,因为我默认的编译路径是:"G:\HowTomcatWorks\JavaWebServer\bin\TestServlet.class",然后我又将这个文件也删了,才提示找不到类文件的错误,真搞不懂……
------------------------------------------
再分割:很复杂,上面写的也不一定对,后来又测试过,如果你看到了这里,那么也请自己测试一下,不能误导自己呀~如有误解,敬请指教,欢迎探讨!