1. 程式人生 > >Socket和ServerSocket的簡單介紹及例子

Socket和ServerSocket的簡單介紹及例子

Socket 類

  socket可以使一個應用從網路中讀取和寫入資料,不同計算機上的兩個應用可以通過連線傳送和接受位元組流,當傳送訊息時,你需要知道對方的ip和埠,在java中,socket指的是java.net.Socket類。 
  在java.net.Socket中,可以看到socket有多種建構函式 
   
  這裡寫圖片描述

  以public Socket(String host, int port)為例,host為遠端機器名稱或ip地址,port為埠號。若連線本地的Server,其埠號為8080,可以寫成如下格式 
  new Socket(“localhost”, 8080); 
  一旦成功建立一個Socket類的例項,可以用它來發送和接收位元組流,傳送時呼叫getOutputStream方法獲取一個java.io.OutputStream物件,接收遠端物件傳送來的資訊可以呼叫getInputStream方法來返回一個java.io.InputStream物件。 

ServerSocket類

  Socket類代表一個客戶端套接字,即任何時候連線到一個遠端伺服器應用時構建所需的socket。現在,要實現一個伺服器應用,需要不同的做法。伺服器需隨時待命,因為不知道客戶端什麼時候會發來請求,此時,我們需要使用ServerSocket,對應的是java.net.ServerSocket類。 
  ServerSocket與Socket不同,ServerSocket是等待客戶端的請求,一旦獲得一個連線請求,就建立一個Socket示例來與客戶端進行通訊。 
  ServerSocket的建構函式也有多種過載形式: 
  這裡寫圖片描述

  ServerSocket 有一個不帶引數的預設構造方法。通過該方法建立的 ServerSocket 不與任何埠繫結,接下來還需要通過 bind()方法與特定埠繫結。這個預設構造方法的用途是,允許伺服器在繫結到特定埠之前,先設定ServerSocket 的一些選項。因為一旦伺服器與特定埠繫結,有些選項就不能再改變了。 
  例如

ServerSocket serverSocket=new ServerSocket();
serverSocket.setReuseAddress(true); //設定 ServerSocket 的選項
serverSocket.bind(new InetSocketAddress(8080)); //與 8080 埠繫結

把以上程式改成

ServerSocket serverSocket=new ServerSocket(8080);
serverSocket.setReuseAddress(true); //設定 ServerSocket 的選項

那 麼 serverSocket.setReuseAddress(true) 方 法 就 不 起 任何作用了 
  我們也可以使用如下建構函式建立一個ServerSocket例項

ServerSocket serverSocket = new ServerSocket(port,3); 

  把連線請求佇列的長度設為 3。這意味著當佇列中有了 3 個連線請求時,如果 Client 再請求連線,就會被 Server拒絕,因為伺服器佇列已經滿了。我們使用的 serverSocket.accept()方法就是從佇列中取出連線請求。 
  總之, 
  客戶端向伺服器傳送請求可分為以下步驟: 
  1.建立一個Socket例項 
  2.利用I/O流與伺服器進行通訊 
  3.關閉socket 
   
  伺服器接收客戶端請求步驟: 
  1.建立一個ServerSocket例項,監聽客戶端發來的請求。 
  2.與客戶端獲取連線後,建立一個Socket例項,利用I/O流與客戶端進行通訊,完畢後關閉Socket。

  當然,伺服器可以接收多個客戶端的請求,所以如果伺服器是一個一個順序相應肯定會帶來不好的體驗,因此使用多執行緒來為多個客戶端提供服務 
Client程式碼:

package com.zhoufenqin.socket.client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;

public class Client {
    public static final int port = 8080;   
    public static final String host = "localhost";
    public static void main(String[] args) {    
        System.out.println("Client Start...");    
        while (true) {    
            Socket socket = null;  
            try {  
                //建立一個流套接字並將其連線到指定主機上的指定埠號  
                socket = new Socket(host,port);    

                //讀取伺服器端資料    
                BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));    
                //向伺服器端傳送資料    
                PrintStream out = new PrintStream(socket.getOutputStream());    
                System.out.print("請輸入: \t");    
                String str = new BufferedReader(new InputStreamReader(System.in)).readLine();    
                out.println(str);    

                String ret = input.readLine();     
                System.out.println("伺服器端返回過來的是: " + ret);    
                // 如接收到 "OK" 則斷開連線    
                if ("OK".equals(ret)) {    
                    System.out.println("客戶端將關閉連線");    
                    Thread.sleep(500);    
                    break;    
                }    

                out.close();  
                input.close();  
            } catch (Exception e) {  
                System.out.println("客戶端異常:" + e.getMessage());   
            } finally {  
                if (socket != null) {  
                    try {  
                        socket.close();  
                    } catch (IOException e) {  
                        socket = null;   
                        System.out.println("客戶端 finally 異常:" + e.getMessage());   
                    }  
                }  
            }  
        }    
    }    
}

Server程式碼:

package com.zhoufenqin.socket.server;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static final int port = 8080;//監聽的埠號     

    public static void main(String[] args) {    
        System.out.println("Server...\n");    
        Server server = new Server();    
        server.init();    
    }    

    public void init() {    
        try {    
            //建立一個ServerSocket,這裡可以指定連線請求的佇列長度  
            //new ServerSocket(port,3);意味著當佇列中有3個連線請求是,如果Client再請求連線,就會被Server拒絕 
            ServerSocket serverSocket = new ServerSocket(port);    
            while (true) {    
                //從請求佇列中取出一個連線
                Socket client = serverSocket.accept();    
                // 處理這次連線    
                new HandlerThread(client);    
            }    
        } catch (Exception e) {    
            System.out.println("伺服器異常: " + e.getMessage());    
        }    
    }    

    private class HandlerThread implements Runnable {    
        private Socket socket;    
        public HandlerThread(Socket client) {    
            socket = client;    
            new Thread(this).start();    
        }    

        public void run() {    
            try {    
                // 讀取客戶端資料    
                BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));    
                String clientInputStr = input.readLine();//這裡要注意和客戶端輸出流的寫方法對應,否則會拋 EOFException  
                // 處理客戶端資料    
                System.out.println("客戶端發過來的內容:" + clientInputStr);    

                // 向客戶端回覆資訊    
                PrintStream out = new PrintStream(socket.getOutputStream());    
                System.out.print("請輸入:\t");    
                // 傳送鍵盤輸入的一行    
                String s = new BufferedReader(new InputStreamReader(System.in)).readLine();    
                out.println(s);    

                out.close();    
                input.close();    
            } catch (Exception e) {    
                System.out.println("伺服器 run 異常: " + e.getMessage());    
            } finally {    
                if (socket != null) {    
                    try {    
                        socket.close();    
                    } catch (Exception e) {    
                        socket = null;    
                        System.out.println("服務端 finally 異常:" + e.getMessage());    
                    }    
                }    
            }   
        }    
    }    
}

結果如下所示: 
這裡寫圖片描述 
這裡寫圖片描述