網路程式設計二(套接字Socket、客戶端和服務端通訊問題)
在客戶機/伺服器工作模式中,在Server端,要準備接受多個Client端計算機的通訊。為此,除用IP地址標識Internet上的計算機之外,另還引入埠號,用埠號標識正在Server端後臺服務的執行緒。埠號與IP地址的組合稱為網路套接字(socket)。
Java語言在實現C/S模式中,套接字分為兩類:
在Server端,ServerSocket類支援底層的網路通訊;
在Client端,Socket類支援網路的底層通訊。
Server機通過埠(匯流排I/O地址)提供面向Client機的服務;Server機在它的幾個不同埠分別同時提供幾種不同的服務。Client接入Server的某一埠,通過這個埠提請Server機為其服務。規定:埠號0~1023供系統專用。例如,HTTP協議在埠80,telnet協議在埠23。埠1024~65535供應用程式使用。
當Client程式和Server程式需要通訊時,可以用Socket類建立套接字連線。套接字連線可想象為一個電話呼叫:最初是Client程式建立呼叫,Server程式監聽;呼叫完成後,任何一方都可以隨時講話。
雙方實現通訊有流式socket和資料報式socket兩種可選方式:
流式socket是有連線的通訊,即TCP(Transmission Control Protocol):每次通訊前建立連線,通訊結束後斷開連線。特點是可以保證傳輸的正確性、可靠性。
資料報式socket是無連線的通訊,即UDP(User Datagram Protocol):將欲傳輸的資料分成 小包,直接上網傳送。無需建立連線和拆除連線,速度快,但無可靠保證。
流式socket在Client程式和Server程式間建立通訊的通道。每個socket可以進行讀和寫兩種操作。對於任一端,與對方的通訊會話過程是:
建立socket連線,獲得輸入/輸出流,讀資料/寫資料,通訊完成後關閉socket(拆除連線)。
利用socket的構造方法,可以在客戶端建立到伺服器的套接字物件:
Socket(String host,int port):host是伺服器的IP地址,port是埠號,這些是預先約定的。
利用ServerSocket的構造方法可以在伺服器建立接受客戶套接字的伺服器套接字物件:
ServerSocket(int port):指定埠號,建立一個ServerSocket物件。埠號port要與客戶呼叫的埠號相同。
伺服器端程式在指定的埠監聽,當收到Client程式發出的服務請求時,建立一個套接字物件與該埠對應的Client程式通訊。例如,執行上述建立伺服器套接字物件的程式碼,確立了物件serverSocket後,就可能它使用accept()方法,得到Socket物件.
package cn.url.day24;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* 客戶端
*/
public class ClientSocketDemo {
public static void main(String[] args) {
DataOutputStream dos = null;
try {
//發起socket請求 開啟socket連結
Socket socket = new Socket("192.168.5.15",9527);
OutputStream os = socket.getOutputStream();
//資料處理流 負責向客戶端傳送資料 同時從鍵盤獲取資料
dos = new DataOutputStream(os);
System.out.println("請輸入任意內容開始傳輸:");
String s=getKeyBoard();//獲取鍵盤資料
while(!s.equals("*")){
System.out.println("請輸入需要傳輸的內容:");
s=getKeyBoard();
dos.writeUTF("你好服務端:"+s);//傳送資料到服務端
}
socket.close();//關閉socket連結
//dos.close();死迴圈時,此處不能關了
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(dos!=null)
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 獲取鍵盤輸入
*/
public static String getKeyBoard(){
InputStreamReader is = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(is);
String s=null;
try {
s = br.readLine();
//return s;
} catch (IOException e) {
e.printStackTrace();
}
return s;
}
}
package cn.url.day24;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
/**
*服務端
*/
public class ServerSocketDemo {
public static void main(String[] args) {
System.out.println("伺服器啟動!");
DataInputStream dis = null;
try {
ServerSocket serverSocket = new ServerSocket(9527);
Socket socket = serverSocket.accept();
InputStream is = socket.getInputStream();
//InputStreamReader isr = new InputStreamReader(is);
dis = new DataInputStream(is);
while(true){
String line = dis.readUTF();
System.out.println("客戶端傳送的資訊是:"+line);
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(dis != null)
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}