330 likes | 443 Views
課程參與度之評估方式. 上課時必須專心聽講,跟上進度,參與討論 扣 分項目 玩線上遊戲一次扣 1 分 玩手機一次扣 1 分 睡覺一次扣 1 分 聊天一次扣 1 分 無法回答老師提出的問題一次扣 1 分 加分項目 主動回答老師的問題一次加 2 分 找出老師程式中的錯誤一次加 1 分 修正老師程式中的錯誤一次加 4 分. 網路程式設計 第六章 伺服器. 鄧姚文. 大綱. ServerSocket 類別 ServerSocket 相關範例 UDP 應用程式. 前言. Client/Server 模式 Server 代表伺服端應用程式
E N D
課程參與度之評估方式 • 上課時必須專心聽講,跟上進度,參與討論 • 扣分項目 • 玩線上遊戲一次扣1分 • 玩手機一次扣1分 • 睡覺一次扣1分 • 聊天一次扣1分 • 無法回答老師提出的問題一次扣1分 • 加分項目 • 主動回答老師的問題一次加2分 • 找出老師程式中的錯誤一次加1分 • 修正老師程式中的錯誤一次加4分
網路程式設計第六章 伺服器 鄧姚文
大綱 ServerSocket類別 ServerSocket相關範例 UDP應用程式
前言 • Client/Server模式 • Server代表伺服端應用程式 • 網頁服務(HTTP) • BBS(TELNET)
前言 • Client/Server模式 • 銀行總行與分行間
6-1ServerSocket類別 • 建構子ServerSocket() • 綁定一個傾聽埠號(Listen Port) • ServerSocket類別有四種建構子 • 執行建構子或方法時,出現埠號被占用或輸出入錯誤等例外情形 • BindException • IOException
6-1ServerSocket類別 • 建構子 • public ServerSocket():無需參數即建立 ServerSocket物件的建構子 • public ServerSocket(int port):建立物件時直接指定傾聽埠號 • public ServerSocket(int port, intqueueLength):建立物件時直接指定傾聽埠號,並設定等待駐列數 • public ServerSocket(int port, intqueueLength, InetAddressbindAddress):此建構子除了建立物件時直接指定傾聽埠號與等待駐列個數外,若主機擁有多個IP位址(多張網路卡)時,可指定傾聽的IP位址
6-1ServerSocket類別 • 方法 • public void bind(SocketAddressep):指定傾聽埠號 • public intgetLocalPort():取得 ServerSocket物件所指定的埠號值,傳回整數值 • public InetAddressgetInetAddress():取得 ServerSocket物件所綁定的IP位址 • Socket accept():開始依照所指定的埠號進行傾聽 • public ServerSocketChannelgetChannel():在「非停頓(non-blocking)」模式之下使用 • public void close():關閉 ServerSocket物件,釋放傾聽的埠號的資源占用
6-1ServerSocket類別 • ServerSocketss = newServerSocket(8888); • Socket socket = ss.accept(); • //連線後,取得輸出入串流 • OutputStream out = socket.getOutputStream(); • InputStream in = socket.getInputStream(); • 伺服器的輸出入串流 • 使用 accept() 方法時,會停頓等待客戶端連線 • 當客戶端連線後回傳一 Socket 物件 • 利用 Socket 物件的 getInputStream與 getOutputStream方法取得輸出入串流
6-2ServerSocket相關範例 • 設計伺服器應用程式時,必須考慮: • 同時多個客戶端連線 • 連線等待負荷 • 多執行緒 • 伺服器資源負荷
6-2ServerSocket相關範例 ▌執行結果 port 21被占用中 port 80被占用中 port 135被占用中 port 445被占用中 port 554被占用中 偵測本機被佔用的埠號-PortScanner
01 package com.ch06; 02 03 import java.io.IOException; 04 import java.net.ServerSocket; 05 06 public class PortScanner { 07 public void scan(){ 08 for (inti=1; i< 65535; i++){ 09 try { 10 ServerSocketss = new ServerSocket(i); 11 } catch (IOException e) { 12 System.out.println("port "+ i + "被占用中"); 13 } 14 } 15 } 16 17 public static void main(String[] args) { 18 PortScannerpserver = new PortScanner(); 19 pserver.scan(); 20 } 21 }
6-2ServerSocket相關範例 執行此程式後,可使用Windows系統內建的telnet程式連線至localhost的8886埠號測試: C:\> telnet localhost 8886 Thu Apr 15 01:29:11 CST 2010 遺失與主機的連線。 C:\> 伺服器傳來的字串 報時伺服器-TimeServer
01 package com.ch06; 02 03 import java.io.IOException; 04 import java.io.PrintWriter; 05 import java.net.ServerSocket; 06 import java.net.Socket; 07 import java.util.Calendar; 08 import java.util.Date; 09 10 public class TimeServer { 11 public TimeServer() { 12 } 13 14 public void report() { 15 try { 16 ServerSocketss = new ServerSocket(8886); 17 Date date = Calendar.getInstance().getTime(); 18 Socket socket = ss.accept();
19 PrintWriter out = new PrintWriter( 20 socket.getOutputStream()); 21 out.println(date); 22 out.flush(); 23 out.close(); 24 socket.close(); 25 ss.close(); 26 } catch (IOException e) { 27 System.out.println("輸出入錯誤"); 28 } 29 } 30 31 public static void main(String[] args) { 32 TimeServertserver = new TimeServer(); 33 tserver.report(); 34 } 35 }
6-2ServerSocket相關範例 執行此程式後,可使用Windows系統內建的telnet程式連線至localhost的8885埠號測試,輸入hello後按下Enter鍵即可得到伺服器回傳回來: C:\> telnet localhost 8885 Hello 遺失與主機的連線。 C:\> ▌EchoServer執行的結果 收到:hello 送出:hello 回音伺服器-EchoServer
01 package com.ch06; 02 03 import java.io.*; 04 import java.net.ServerSocket; 05 import java.net.Socket; 06 07 public class EchoServer { 08 public void echo() { 09 try { 10 ServerSocketss = new ServerSocket(8885); 11 Socket socket = ss.accept(); 12 // 連線後,取得輸出入串流 13 OutputStreamrawOut = socket.getOutputStream(); 14 InputStreamrawIn = socket.getInputStream(); 15 PrintWriter out = new PrintWriter(rawOut); 16 BufferedReader in = new BufferedReader( 17 new InputStreamReader(rawIn)); 18 // 等待客戶端送來字串
19 String data = in.readLine(); 20 System.out.println("收到:" + data); 21 // 將傳來的資料回送給客戶端 22 out.println(data); 23 out.flush(); 24 System.out.println("送出:" + data); 25 // 關閉連線資源 26 in.close(); 27 out.close(); 28 socket.close(); 29 ss.close(); 30 } catch (IOException e) { 31 System.out.println("輸出入錯誤"); 32 } 33 } 34 35 public static void main(String[] args) { 36 EchoServereserver = new EchoServer(); 37 eserver.echo(); 38 } 39 }
6-2ServerSocket相關範例 執行CounterServer類別後,可使用Windows系統內建的telnet程式連線至localhost的8884埠號測試,多執行幾次,可看出持續計次的效果: C:\> telnet localhost 8884 您是第1個客戶端 遺失與主機的連線。 C:\> telnet localhost 8884 您是第2個客戶端 遺失與主機的連線。 C:\> telnet localhost 8884 您是第3個客戶端 遺失與主機的連線。 C:\> 計算客戶端連線次數-CounterServer
01 package com.ch06; 02 03 import java.io.*; 04 import java.net.ServerSocket; 05 import java.net.Socket; 06 07 public class CounterServer { 08 public static int count = 0; 09 10 public void startCount() { 11 while (true) { 12 try { 13 ServerSocketss = new ServerSocket(8884); 14 Socket socket = ss.accept(); 15 count++; 16 System.out.println("第" + count + "個客戶連線成功"); 17 OutputStreamrawOut = socket.getOutputStream(); 18 PrintWriter out = new PrintWriter(rawOut);
19 out.println("您是第" + count + "個客戶端"); 20 out.flush(); 21 out.close(); 22 socket.close(); 23 ss.close(); 24 } catch (IOException e) { 25 System.out.println("輸出入錯誤"); 26 } 27 } 28 } 29 30 public static 31 CounterServercserver = new CounterServer(); 32 cserver.startCount(); 33 } 34 }
6-3UDP應用程式 • DatagramPacket • 建立UDP封包 • 定義了UDP封包的格式與資訊 • 對方(伺服端)的IP位址 • 埠號 • 欲傳送的資料
6-3UDP應用程式 • DatagramPacket • 建構子 • public DatagramPacket(byte[] data, int length, InetAddress dest, int port) • public DatagramPacket(byte[] data, int offset, int length, InetAddress dest, int port) • public DatagramPacket(byte[] data, int length, SocketAddress dest) • public DatagramPacket(byte[] data, int length, SocketAddress dest) • public DatagramPacket(byte[] buffer, int length) • PublicDatagramPacket(byte[]butter,intoffset,intlength)
6-3UDP應用程式 • DatagramPacket • DatagramPacket方法 • public byte[] getData():取得UDP封包內的資料 • public InetAddress getAddress():得到UDP封包的IP位址物件 • public int getPort():得到UDP封包的埠號值 • public int getLength():得到UDP封包的資料長度 • public void setData(byte[] data):設定封包內的資料,傳入一個位元組陣列。 • public void setAddress(InetAddress addr):設定封包內的位址,傳入一個位址物件。 • public void setPort(int port):設定封包內的埠號值,傳入一整數。 • public void setLength(int length):定封包的資料個數(長度),傳入一個整數。
6-3UDP應用程式 • DatagramSocket • 傳送UDP封包 • 接收時,需要占用一個本機的埠號 • 傳送時,時不需指令埠號
6-3UDP應用程式 • DatagramSocket • 建構子 • DatagramSocket() • DatagramSocket(int port) • DatagramSocket(int port, InetAddress addr)
6-3UDP應用程式 • DatagramSocket • DatagramSocket方法 • void connect(InetAddress addr, int port):依傳入的位址與埠號參數與遠端主機建立連線,可用來傳送UDP封包至特定遠端主機。 • void disconnect():切斷連線。 • DatagramChannel getChannel():得到NIO的UDP封包頻道。 • void receive(DatagramPacket p):執行到此方法時會開始等待外來封包到達 • void send(DatagramPacket p):依照p封包內所事先定義的位址與埠號,將p封包傳送至遠端主機。
6-3UDP應用程式 • UDPClient/Server範例 • 送出UDP封包(客戶端)-UDPClient
01 package com.ch06; 02 03 import java.io.IOException; 04 import java.net.DatagramPacket; 05 import java.net.DatagramSocket; 06 import java.net.InetAddress; 07 08 public class UDPClient { 09 public static void main(String[] args) throws IOException { 10 InetAddressaddr = InetAddress.getLocalHost(); 11 String data = "ABC"; 12 byte[] buf = data.getBytes(); 13 DatagramPacketpkt = new DatagramPacket(buf, buf.length, 14 addr, 9950); 15 DatagramSocketds = new DatagramSocket(); 16 ds.send(pkt); 17 } 18 }
6-3UDP應用程式 • UDPClient/Server範例 • 接收UDP封包(伺服端)-UDPServer
01 package com.ch06; 02 03 import java.io.IOException; 04 import java.net.DatagramPacket; 05 import java.net.DatagramSocket; 06 07 public class UDPServer { 08 public static void main(String[] args) throws IOException { 09 byte[] buffer = new byte[10]; 10 DatagramPacketpkt = new DatagramPacket(buffer, 10); 11 DatagramSocketds = new DatagramSocket(9950); 12 System.out.println("正在等待埠號:" + ds.getLocalPort()); 13 ds.receive(pkt); 14 System.out.println("已收到UDP封包,封包內容:"); 15 for (inti = 0; i < buffer.length; i++) 16 System.out.print(buffer[i]); 17 } 18 }
6-3UDP應用程式 • 簡易監測協定 • 1. 伺服端應用程式(被偵測方) • 假設伺服器的IP位址是192.168.1.10 • 持續在埠號9970等待(接收)外來UDP封包 • 收到封包後取得封包內的資料,檢查資料是否為「AYT」字串,若符合,則將一個資料內容為「Everything is fine.」的UDP封包送至詢問端電腦位址的埠號9971。 • 2.客戶端應用程式(偵測方) • 主動傳送查詢封包至伺服器(192.168.1.10)的埠號9970,封包內容是「AYT」 • 等待並接收伺服器的回應封包,並檢視內容 • 結束程式
本章結束 Q&A討論時間