最近在看,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",然後我又將這個文件也刪了,才提示找不到類文件的錯誤,真搞不懂……
------------------------------------------
再分割:很複雜,上面寫的也不一定對,後來又測試過,如果你看到了這裏,那麼也請自己測試一下,不能誤導自己呀~如有誤解,敬請指教,歡迎探討!