Java網絡編程_基於TCP協議的網絡編程(一)

TCP/IP通信協議是一種可靠的網絡協議,它在通信的兩端各建立一個Socket,從而在通信的兩端之間形成網絡虛擬鏈路。一旦建立了虛擬網絡鏈路,兩端的程序就可以通過虛擬鏈路進行通信。Java對基於TCP協議的網絡通信提供了良好的封裝,Java使用Socket對象來代表兩端的通信端口,並通過Socket產生IO流進行網絡通信。

使用ServerSocket創建TCP服務器端

在兩個通信實體之間並沒有服務器端和客戶端之分,但在兩個通信實體沒有建立虛擬鏈路之前,必須有一個通信實體先做出“主動姿態”,主動接收來自其他通信實體的連接請求。

Java中能接收其他通信實體連接請求的類是ServerSocket,ServerSocket對象用於監聽來自客戶端的Socket連接,如果沒有連接,它將一直處於等待狀態。ServerSocket包含一個監聽來自客戶端請求的方法。

方法
Socket accept() 如果接收到一個客戶端Socket的連接請求,該方法將返回一個與客戶端Socket對應的Socket(每個TCP連接有兩個Socket)否則該方法將一直處於等待狀態,線程也被阻塞
ServerSocket所提供的構造器
ServerSocket(int port) 用指定的端口port來創建一個ServerSocket。該端口應該有一個有效的端口數值,即0~65535
ServerSoccket(int port,int backlog) 增加一個用來改變連接隊列長度的參數backlog
ServerSocket(int port,int backlog,InetAddress localAddr) 在機器存在多個IP地址的情況下,允許通過localAddr參數來指定將ServerSocket綁定到指定的IP地址。

使用Socket進行通信

客戶端通常可以使用Socket的構造器來連接到指定服務器,Socket通常可以使用如下兩個構造器。

構造器
Socket(InetAddress/String remoteAddress,int port) 創建連接到指定遠程主機、遠程端口的Socket,該構造器沒有指定本地地址、本地端口,默認使用本地主機的默認IP地址,默認使用系統動態分配的端口
Socket(InetAddress/String remoteAddress,int port,InetAddress localAddr,int localPort) 創建連接到指定遠程主機、遠程端口的Socket,並指定本地IP地址和本地端口,適用於本地主機有多個IP地址的情形

當客戶端、服務器端產生了對應的Socket之後,程序無須再區分服務器端、客戶端,而是通過各自的Socket進行通信。Socket提供了兩個方法來獲取輸入流和輸出流。

方法
InputStream getInputStream() 返回該Socket對象對應的輸入流,讓程序通過該輸入流從Socket中取出數據
OutputStream getOutputStream() 返回該Socket對象對應的輸出流,讓程序輸出流向Socket中輸出數據

代碼示例,一個簡單的通訊
服務端:

public class Server {

    public static void main(String[] args) throws IOException{

        //創建一個ServerSocket,用於監聽客戶端Socket的連接請求
        ServerSocket ss = new ServerSocket(30000);
        //採用循環換不斷地接收來自客戶端的請求
        while (true){
            //每當接收到客戶端Socket的請求時,服務器端也對應產生一個Socket
            Socket s = ss.accept();
            //將Socket對應的輸出流包裝成PrintStream
            PrintStream ps = new PrintStream(s.getOutputStream());
            //進行普通的IO操作
            ps.println("您好,您收到了服務器的問候!");
            //關閉輸出流,關閉Socket
            ps.close();
            s.close();
        }
    }
}

客戶端:

public class Client {

    public static void main(String[] args) throws IOException{
        //其中“1227.0.0.1”代表本機的IP地址,因爲服務端和客戶端都是在本機運行
        Socket socket = new Socket("127.0.0.1", 30000);
        //將Socket對應的輸入流包裝成BufferedReader
        BufferedReader br = new BufferedReader(
        new InputStreamReader(socket.getInputStream()));
        //進行普通IO操作
        String line = br.readLine();
        System.out.println("來自服務器的數據:" + line);
        //關閉輸入流,關閉Socket
        br.close();
        socket.close();
    }
}

在實際應用中,程序可能不想讓執行網絡連接、讀取服務器數據的進程一直阻塞,而是希望當網絡連接、讀取操作超過合理時間之後,系統自動認爲操作失敗,這個合理時間就是超時時長。(在指定時間內通信未到達,斷開連接)

//Socket對象提供了一個setSoTimeout(int timeout)方法來設置超時時長
Socket s = new Socket("127.0.0.1", 30000);
//設置10秒之後即認爲超時
s.setSoTimeouut(10000);

當Socket連接服務器超過指定時長,進行處理。

//創建一個無連接的Socket
Socket s = new Socket();
//讓該Socket連接到遠程服務器,如果經過10秒還未連接上,則認爲連接超時
s.connect(new InetSocketAddress (host,port),10000);

兩種超時的區別,第一種是讀寫超時,在已經連通,但在通信過程中,某條信息的傳送超過指定時間,報錯。第二種是鏈接超時,還未連通,連接時間超過指定時間,報錯。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章