前幾天在本區看到一個(gè)貼子,有人問(wèn),在Socket做服務(wù)器,在手機上用Http訪(fǎng)問(wèn),如何實(shí)現。這個(gè)貼子,有十來(lái)個(gè)人回復了,可惜回復的都是:Socket使用TCP/IP協(xié)議,客戶(hù)端用HTTP協(xié)議,不同協(xié)議不可能實(shí)現通訊。再可惜,那個(gè)貼子結了,要不然,我就可以回復了!在這里拿出來(lái)說(shuō)一下,讓大家不要再誤會(huì )了(TCP/IP與HTTP不可通訊)
因為目前很多手機仍不支持MIDP2.0,只支持MIDP1.0,而Socket技術(shù)只在MIDP2.0才提供支持,所以,一般的Java ME程序的如果要實(shí)現C/S結構,都會(huì )選用Tomcat等服務(wù)器、sevlet或JavaBean等Java EE架構實(shí)現。不過(guò),考慮到響應速度與性能的問(wèn)題,Tomcat等Java EE架構可能滿(mǎn)足不了業(yè)務(wù)要求,這樣,我們就要用到下面將要說(shuō)的自已寫(xiě)服務(wù)器的技術(shù)了。
一般的C/S結構程序,一般程序員都會(huì )寫(xiě),不過(guò),這里一般程序員剛接觸Socket寫(xiě)服務(wù)器,Http寫(xiě)客戶(hù)端都會(huì )頭大——不可能吧,Socket用TCP/IP協(xié)議,客戶(hù)端用Http協(xié)議,不同協(xié)議間,怎么可能通訊呢!
本文要說(shuō)的就是這個(gè)問(wèn)題了。
大家一定都知道,網(wǎng)絡(luò )系統一共分7層,在這七層中,Http協(xié)議要高于TCP/IP協(xié)議(因為在互聯(lián)網(wǎng)中,計算機是通過(guò)IP定位的,也就是用TCP/IP協(xié)議了),對網(wǎng)絡(luò )操作系統有了解的人,一定不會(huì )忘記,我們用Http訪(fǎng)問(wèn)www的時(shí)候,用的是域名,而域名,最終還是要通過(guò)DNS轉換成IP地址的。這就對了——HTTP協(xié)議基于TCP/IP協(xié)議!而Socket正是基于TCP/IP協(xié)議,這樣一來(lái),它們就有了共同之外了!有了以上的認識,理論方面就沒(méi)問(wèn)題了。
我們再討論一下實(shí)現:
服務(wù)器:
和一般的C/S結構一樣,用Socket(java中用ServerSocket)監聽(tīng)。監聽(tīng)、讀寫(xiě)消息的方面與一般的C/S服務(wù)器一模一樣。不同的是,考慮到客戶(hù)端只支持http協(xié)議,所以,讀客戶(hù)端消息的時(shí)候,讀到的將是http頭+消息,那么,我們便要用程序分析并去掉http頭,只用消息。發(fā)消息的時(shí)候正好相反,在發(fā)送的消息前面,自己加上http頭(其實(shí)就是一個(gè)包含一定內容的字符串),這樣再發(fā)出去,客戶(hù)端就可以收到并讀取了。
客戶(hù)端:
用Http連接,在java中,用的是HttpConnection.open("http://"+IP+":"+Port)訪(fǎng)問(wèn)服務(wù)器,這樣,就可以向ServerSocket請求連接了。
在open之后,再向HttpConnection對象的輸出流寫(xiě)入消息,然后刷新流再關(guān)閉HttpConnection就可以了,客戶(hù)端因為本來(lái)用的就是http協(xié)議,所以不用自行加http頭,底層會(huì )處理的;服務(wù)器在A(yíng)ccept()之后,就可以從Socket的輸入流讀到消息了。當然,如果要讀服務(wù)器的消息的話(huà),可以在HttpConnection關(guān)閉前讀它的輸入流(讀的時(shí)候,如果還沒(méi)有收到服務(wù)器消息,會(huì )阻塞當前線(xiàn)程的,直到讀到為止,不怕讀不到)??蛻?hù)端讀到的消息,是不包括http頭的,所以,也就不用我們自行處理了。
要注意的是,HttpConnetion.open后,只能用一次,刷新后,它就無(wú)效了,得重新調用open方法再次建立連接。(服務(wù)器最好使用線(xiàn)程建立Socket與客戶(hù)端連接,連接一次一個(gè)線(xiàn)程。)
服務(wù)器示例代碼:(共三個(gè)類(lèi)) //HttpServer.java package testnetserver; public class HttpServer{ public HttpServer() { } public static void main(String[] aregs){ HttpServerSocket hss=new HttpServerSocket(); hss.start(); } } //HttpServerSocket.java package testnetserver; import java.net.ServerSocket; import java.io.*; public class HttpServerSocket extends Thread{ ServerSocket ss=null; private static final int port=2222; public HttpServerSocket() { } public void run(){ try { ss = new ServerSocket(port); } catch (IOException ex) { System.out.println("ServerSocket can not listen"); System.out.println("Error on ServerSocket bind port"); ex.printStackTrace(); ss=null; return; } //循環(huán)監聽(tīng) while(true){ HttpSocket hs=null; try { hs=new HttpSocket(); hs.s=ss.accept(); System.out.println("have a client connect"); hs.start(); } catch (IOException ex1) { System.out.println("Error on accept"); } } } } //HttpSocket.java package testnetserver; import java.net.Socket; import java.io.*; public class HttpSocket extends Thread { public Socket s = null; String msg = ""; public HttpSocket() { } public void run() { BufferedReader is = null; PrintWriter os = null; try { //由Socket對象得到輸入流,并構造相應的BufferedReader對象 is = new BufferedReader(new InputStreamReader(s.getInputStream())); //由Socket對象得到輸出流,并構造PrintWriter對象 os = new PrintWriter(s.getOutputStream()); } catch (IOException ex) { System.out.println("Error on get Buffere"); } String temp = ""; try { temp = is.readLine(); while (temp != null) { msg += temp; if (temp.length() > 4 && temp.substring(temp.length() - 4).equals("/End")) { temp = is.readLine(); //虛讀 temp = null; break; } msg += "\r\n"; temp = is.readLine(); } getMsg(); //立刻回發(fā)消息 msg = "Begin/" + msg + "/End"; os.write("HTTP/1.1 200 OK\r\n"); os.write("Content-Type: text; charset=utf\r\n"); os.write( ("Content-Length: " + msg.length() + "\r\n")); os.write("\r\n"); os.write(msg); os.flush(); msg = ""; } catch (IOException ex1) { System.out.println("Error on read or write Buffered"); ex1.printStackTrace(); } try { sleep(100); } catch (InterruptedException ex2) { System.out.println("Error on HttpSocket sleep"); } } //去掉協(xié)議頭,取出純消息 private void getMsg() { int begin = msg.indexOf("Begin/"); int end = msg.indexOf("/End"); if (begin >= 0 && end > 0 && msg.length()>"Begin/".length()) { msg = msg.substring(begin + "Begin/".length(), end); System.out.println(msg); } else { msg = ""; } } }
聯(lián)系客服