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());
}
}
}
}
}
}
結果如下所示: