1 簡單通信
??回顧 Socket 編程給我們最大的感受,是可以在多臺電腦之間進行數據的傳輸,這就是網絡編程的開端和基礎,通過客戶端請求服務器端通信,直觀了解 Web 編程。
Server
/**
* 服務端,接收客戶端請求并給出簡單的響應
* @author Cushier
*
*/
publicclassServer{
? ? publicstaticvoidmain(String[]args)throwsIOException{
? ? ? ? // 創(chuàng)建服務器,指定端口ServerSocket(int port)
? ? ? ? ServerSocketsocket=newServerSocket(8888);
? ? ? ? // 接收客戶端連接
? ? ? ? Socketclient=socket.accept();
? ? ? ? System.out.println("******************");
? ? ? ? // 獲取數據的輸入流
? ? ? ? InputStreamis=client.getInputStream();
? ? ? ? // 使用緩沖字符輸入流
? ? ? ? BufferedReaderbr=newBufferedReader(newInputStreamReader(is));
? ? ? ? Stringmsg="";
? ? ? ? while((msg=br.readLine())!=null) {
? ? ? ? ? ? System.out.println(msg);
? ? ? ? }
? ? ? ? br.close();
? ? }
}
Client
/**
* 客戶端:向服務器發(fā)送請求,并發(fā)送簡單的消息
* @author Cushier
*
*/
publicclassClient{
? ? publicstaticvoidmain(String[]args)throwsUnknownHostException,IOException{
? ? ? ? // 創(chuàng)建客戶端 必須指定服務器+端口
? ? ? ? Socketclient=newSocket("localhost",8888);
? ? ? ? // 發(fā)送消息 請求資源
? ? ? ? // 獲取輸出流
? ? ? ? OutputStreamos=client.getOutputStream();
? ? ? ? // 使用緩沖字符輸出流
? ? ? ? BufferedWriterbr=newBufferedWriter(newOutputStreamWriter(os));
? ? ? ? // 寫出消息,發(fā)送內容
? ? ? ? Stringmsg="Hello, I am Client, I need some resources";
? ? ? ? br.write(msg);
? ? ? ? br.close();
? ? }
}
服務端控制臺:
從上面的例子總結通信條件如下:
需要有服務器端(server):等待被請求,需要暴露 ip 和 port
需要有客戶端(client):主動發(fā)起請求,知曉服務端的 ip 和 port
通信規(guī)則(協(xié)議):TCP/IP 協(xié)議
??ip 用于定位計算機;端口號(定位程序),用于標識進程的邏輯地址,不同進程的標志;有效端口:0~65535,其中 0~1024 由系統(tǒng)使用或者保留端口,開發(fā)中建議使用 1024 以上的端口。
2 不同請求
Client
/**
* 客戶端:向服務器發(fā)送請求,發(fā)送不同的請求
* @author Cushier
*
*/
publicclassClient{
? ? publicstaticvoidmain(String[]args)throwsIOException{
? ? ? ? // 通過系統(tǒng)默認類型的 SocketImpl 創(chuàng)建未連接套接字
? ? ? ? Socketsocket=newSocket();
? ? ? ? // 此類實現 IP 套接字地址(IP 地址 + 端口號)。它還可以是一個對(主機名 + 端口號),在此情況下,將嘗試解析主機名
? ? ? ? SocketAddressaddress=newInetSocketAddress("localhost",8898);
? ? ? ? // 將此套接字連接到服務器,并指定一個超時值。或者不指定超時時間
? ? ? ? socket.connect(address,1000);
? ? ? ? OutputStreamos=socket.getOutputStream();
? ? ? ? os.write("time".getBytes());
? ? ? ? os.flush();
? ? ? ? socket.close();
? ? }
}
Server
/**
* 服務端
* public class ServerSocketextends Object:此類實現服務器套接字。
* 服務器套接字等待請求通過網絡傳入。
* 它基于該請求執(zhí)行某些操作,然后可能向請求者返回結果。
*
* @author Cushier
*
*/
publicclassServer{
? ? publicstaticvoidmain(String[]args)throwsIOException{
? ? ? ? // 創(chuàng)建綁定到特定端口的服務器套接字。
? ? ? ? ServerSocketserver=newServerSocket(8898);
?
? ? ? ? // Socket accept() 偵聽并接受到此套接字的連接。
? ? ? ? Socketclient=server.accept();
? ? ? ? System.out.println("接收到連接");
?
? ? ? ? InputStreamis=client.getInputStream();
? ? ? ? BufferedInputStreambis=newBufferedInputStream(is);
? ? ? ? byte[]req=newbyte[1024];
? ? ? ? // 接收客戶端請求
? ? ? ? intlen=bis.read(req);
? ? ? ? StringreqStr=newString(req,0,len);
? ? ? ? System.out.println(reqStr);
? ? ? ? if(reqStr.equals("money")) {
? ? ? ? ? ? System.out.println("here's the money");
? ? ? ? }elseif(reqStr.equals("time")) {
? ? ? ? ? ? System.out.println("you have so much time");
? ? ? ? }
? ? ? ? client.close();
? ? ? ? server.close();
? ? }
}
服務端控制臺:
3 復雜請求
Client
/**
* 客戶端
*
* @author Cushier
*
*/
publicclassClient{
? ? publicstaticvoidmain(String[]args)throwsIOException{
? ? ? ? // 通過系統(tǒng)默認類型的 SocketImpl 創(chuàng)建未連接套接字
? ? ? ? Socketsocket=newSocket();
? ? ? ? // 此類實現 IP 套接字地址(IP 地址 + 端口號)。它還可以是一個對(主機名 + 端口號),在此情況下,將嘗試解析主機名
? ? ? ? SocketAddressaddress=newInetSocketAddress("localhost",8898);
? ? ? ? // 將此套接字連接到服務器,并指定一個超時值?;蛘卟恢付ǔ瑫r時間
? ? ? ? socket.connect(address,1000);
?
? ? ? ? OutputStreamos=socket.getOutputStream();
? ? ? ? os.write("money".getBytes());
? ? ? ? os.flush();
? ? ? ? // 接收響應,顯示結果
? ? ? ? InputStreamis=socket.getInputStream();
? ? ? ? byte[]result=newbyte[1024];
? ? ? ? intlen=is.read(result);
? ? ? ? StringresultStr=newString(result,0,len);
? ? ? ? System.out.println(resultStr);
? ? ? ? socket.close();
? ? }
}
Server
/**
* 服務端
* @author Cushier
*
*/
publicclassServer2{
? ? publicstaticvoidmain(String[]args)throwsIOException{
? ? ? ? // 創(chuàng)建綁定到特定端口的服務器套接字。
? ? ? ? ServerSocketserver=newServerSocket(8898);
?
? ? ? ? // Socket accept() 偵聽并接受到此套接字的連接。
? ? ? ? Socketclient=server.accept();
? ? ? ? System.out.println("接收到連接");
? ? ? ? InputStreamis=client.getInputStream();
? ? ? ? BufferedInputStreambis=newBufferedInputStream(is);
? ? ? ? byte[]req=newbyte[1024];
? ? ? ? // 接收客戶端請求
? ? ? ? intlen=bis.read(req);
? ? ? ? StringreqStr=newString(req,0,len);
? ? ? ? System.out.println(reqStr);
? ? ? ? // 將接收到的請求封裝成對象,傳送給請求的類
? ? ? ? MyRequestrequest=newMyRequest();
? ? ? ? MyResponseresponse=newMyResponse();
?
? ? ? ? OutputStreamos=client.getOutputStream();
? ? ? ? if(reqStr.equals("money")) {
? ? ? ? ? ? // 根據請求的信息,構造處理的類
? ? ? ? ? ? MyServlets1=newServletMoney();
? ? ? ? ? ? s1.service(request,response);
? ? ? ? ? ? // 通過client的響應,將結果響應回客戶端
? ? ? ? ? ? os.write("here's the money".getBytes());
? ? ? ? ? ? os.flush();
? ? ? ? }elseif(reqStr.equals("time")) {
? ? ? ? ? ? // 根據請求的信息,構造處理的類
? ? ? ? ? ? MyServlets2=newServletTime();
? ? ? ? ? ? s2.service(request,response);
? ? ? ? ? ? // 通過client的響應,將結果響應回客戶端
? ? ? ? ? ? os.write("you have somuch time".getBytes());
? ? ? ? ? ? os.flush();
? ? ? ? }
? ? ? ? client.close();
? ? ? ? server.close();
? ? }
}
?
/*
* 我是一個有要求的人,你請求的這個資源必須是滿足我要求格式的類,作用:防止混亂,方便調用 這是我的標準
*/
interfaceMyServlet{
? ? voidservice(MyRequestreq,MyResponseresp);
}
?
classServletMoneyimplementsMyServlet{
? ? @Override
? ? publicvoidservice(MyRequestreq,MyResponseresp) {
? ? ? ? // 做出力所能及的處理
? ? }
}
?
classServletTimeimplementsMyServlet{
? ? @Override
? ? publicvoidservice(MyRequestreq,MyResponseresp) {
? ? ? ? // 做出力所能及的處理
? ? }
}
?
/*
* 請求信息都按規(guī)律封裝在該對象
*/
classMyRequest{
}
?
classMyResponse{
}
服務端控制臺:? 客戶端控制臺:
??隨著客戶需求越來越復雜,需要的功能越來越多,我們的服務器端需要處理的請求越來越多,需要區(qū)分不同的請求,還需要按照不同請求進行請求數據的提取以及資源的分配和運算還有邏輯的處理,最后還需要響應給客戶端,這就使得服務器端代碼越來越復雜,實現越來越困難。
??根據以往的經驗,雙方進行通信只需要遵循一定的規(guī)則就可以很明確地知道各部分數據的含義,于是出現了網絡更上層的應用協(xié)議(后面講的 HTTP 協(xié)議),規(guī)定服務器端和客戶端通信的規(guī)則。
??客戶端請求服務器端和服務器端響應客戶端,都按照固定的規(guī)則,那么接收請求和響應數據這部分操作就可以固定下來,交給特定的一段代碼來執(zhí)行,從而減少服務器端的代碼量,于是出現了接下來說的服務器。
擴展
服務器的出現
??當客戶端請求的資源越來越豐富,需求越來越復雜,程序的核心就應該放在解決業(yè)務和計算響應數據上,于是出現了服務器統(tǒng)一接收客戶端數據進行處理并分發(fā)到不同的資源,由各個資源進行處理,最后結果交由服務器響應。
??從上面的描述可以發(fā)現,現在所說的服務器只是負責接收請求,對請求進行分發(fā),以及最后將獲取的數據進行相應的固定框架,至于數據怎么計算得出還得根據具體的業(yè)務需求編寫(填充)代碼。在沒有業(yè)務需求的情況下就能將服務器準備出來,現在市面上的服務器有很多,比較常用的有:Tomcat、JBOOS、IBM 的 WebSphere、BEA的 WebLogic 以及 Apache 等。