1. 程式人生 > >網路程式設計二(套接字Socket、客戶端和服務端通訊問題)

網路程式設計二(套接字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是埠號,這些是預先約定的。

用getInputStream()方法獲得輸入流,用這個輸入流讀取伺服器放入“線路”的資訊;用getOutputStream()方法獲得輸出流,用這個輸出流將資訊寫入“線路”。

利用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();
				}
		}
	}
}