Java ServerSocket詳解

ServerSocket

構造方法

ServerSocket serverSocket = new ServerSocket();
ServerSocket();		//無參數
ServerSocket(int port);		//指定端口
ServerSocket(int port,int backlog);		//指定端口、隊列數
ServerSocket(int port,int backlog,InetAddress bindAddr);	//指定端口、隊列數、綁定IP

注:當port爲0時,隨機分配空閒端口。java

無參數綁定端口

serverSocket.bind(SocketAddress endpoint);	//指定端口
serverSocket.bind(SocketAddress endpoint,int backlog)	//指定端口、隊列數

ServerSocket選項

SO_TIMEOUT:等待客戶鏈接的超時時間

serverSocket.setSoTimeout(int timeout);		//設置(單位爲毫秒,爲0,則永不超時)
serverSocket.getSoTimeout();		//查看超時時間

SO_REUSEADDR:是否容許重用服務器所綁定的地址(需在鏈接前設置)

serverSocket.setResuseAddress(boolean on);	//設置
serverSocket.getResuseAddress();		//查看是否開啓

SO_RCVBUF:接收數據的緩衝區大小

serverSocket.setReceiveBufferSize(int size);	//設置
serverSocket.getReceiveBufferSize();	//查看緩衝區大小

設定鏈接時間、延遲和帶寬

參數(相對權重)

三個參數之間的相對大小決定相應參數的相對重要性。服務器

  • connectionTime:最少時間創建鏈接
  • latency:最小延遲
  • bandwidth:最高帶寬
serverSocket.setPerformancePreferences(int connectionTime,int latency,int bandwidth);	//設置

ServerSocket信息

serverSocket.getInetAddress();	//獲取服務器綁定的IP
serverSocket.getLocalPort();	//獲取服務器綁定的端口

多線程

爲每個鏈接建立一個線程

重寫Runnable方法

Handler.java
package Network_3;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;

public class Handler implements Runnable {
	private Socket socket = null;		//初始化Socket
	public Handler(Socket socket) {
		this.socket = socket;			//傳入參數
	}
    /*
    *	輸出流
    */
	public PrintWriter getWriter(Socket socket) throws IOException {
		OutputStream socketOut = socket.getOutputStream();
		return new PrintWriter(socketOut,true);
	}
    /*
    *輸入流
    */
	public BufferedReader getReader(Socket socket) throws IOException {
		InputStreamReader socketIn = new InputStreamReader(socket.getInputStream());
		return new BufferedReader(socketIn);
	}
    //加工信息
	public String Echo(String msg) {
		return "Echo:"+msg;
	}
	public void run() {
		try {
			System.out.println("New Connection "+socket.getInetAddress()+":"+socket.getPort());	//打印新鏈接信息
			BufferedReader br = getReader(socket);	//輸入流
			PrintWriter pw = getWriter(socket);		//輸出流
			String msg = null;		//初始化msg
			while((msg = br.readLine()) != null) {	//循環讀取一行信息
				System.out.println(msg);			//打印信息
				pw.println(Echo(msg));				//將信息加工發送回客戶端
				if(msg.equals("exit")) {			//結束條件
					break;
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			try {
				if(socket != null) {			//若有鏈接,關閉
					socket.close();
				}
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}
Server.java
package Network_3;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
	private int port = 8000;	//初始化port
	private ServerSocket serverSocket = null;	//初始化ServerSocket
	public Server() {
		try {
			serverSocket = new ServerSocket(port);	//啓動服務端
			System.out.println("Server Up!");
		} catch (IOException e) {
			System.out.println("Server Up Error!");
		}
	}
	public void service() {
		while(true) {
			Socket socket = null;		//初始化Socket
			try {
				socket = serverSocket.accept();	//監聽鏈接隊列
				Thread workThread = new Thread(new Handler(socket)); //建立線程
				workThread.start();		//啓動線程
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	public static void main(String[] args) {
		new Server().service();
	}
}
Client.java
package Network_3;

import java.net.*;
import java.io.*;

public class Client {
	/*
	 * 參數初始化
	 */
	private String host = "127.0.0.1";
	private int port = 8000;
	private Socket socket;
	/*
	 * 創建鏈接
	 */
	public Client() throws IOException {
		socket = new Socket(host,port);
	}
	/*
	 * 輸出流
	 */
	private PrintWriter getWriter(Socket socket) throws IOException {
		OutputStream socketOut = socket.getOutputStream();
		return new PrintWriter(socketOut,true);
	}
	/*
	 * 輸入流
	 */
	private BufferedReader getReader(Socket socket) throws IOException {
		InputStreamReader socketIn = new InputStreamReader(socket.getInputStream());
		return new BufferedReader(socketIn);
	}
	/*
	 * 客戶程序
	 */
	public void Talk() {
		try {
			BufferedReader br = getReader(socket);
			PrintWriter pw = getWriter(socket);
			BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in));
			String msg = null;
			while((msg = localReader.readLine()) != null) {
				pw.println(msg);
				System.out.println(br.readLine());
				if(msg.equals("exit")) {
					break;
				}
			}
		}catch (Exception e) {
				e.printStackTrace();
		}finally {
			try {
				socket.close();
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	public static void main(String[] args) throws UnknownHostException, IOException {
		new Client().Talk();
	}
}

使用JDK類庫提供的線程池

java.util.concurrent包提供

Server.java
package Network_3;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server {
	private int port  = 8000;		//初始化port
	private ServerSocket serverSocket = null;		//初始化ServerSocket
	private ExecutorService executorService = null;	//初始化線程池
	private final int POOL_SIZE = 4;	//單個CPU的線程數
	
	public Server() throws IOException {
		serverSocket = new ServerSocket(port);
		executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_SIZE);		//建立線程池,Runtime.getRuntime().availableProcessors()用於返回當前工做環境的CPU數,將CPU數乘單個CPU線程數,獲得最終的總線程數。
		System.out.println("Server Up");
	}
	
	public void service() {
		while(true) {
			Socket socket = null;
			try {
				socket = serverSocket.accept();
				executorService.execute(new Handler(socket));	//Handler與上面的同樣
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	public static void main(String[] args) throws IOException {
		new Server().service();
	}
}

注意事項

死鎖

建議:儘可能減小任務之間的依賴。多線程

系統資源不足

建議:根據系統性能設定線程數,回收機制。併發

併發錯誤

建議:使用成熟的線程技術。socket

線程泄露

建議:執行線程任務時,減小與用戶的交互(使用超時機制)。性能

任務過載

建議:控制線程等待隊列中的線程數。this

關閉服務器

開放一個管理服務器端口,啓動守護線程,供管理程序鏈接,當發送特定字符時,服務器中止向線程池添加任務並等待任務執行完畢或超時,關閉服務程序。spa

Server.java
package Network_3;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;

public class Server {
	private int port = 8000;		//服務端口
	private ServerSocket serverSocket = null;	//服務Socket
	private ExecutorService executorService = null;	//線程池
	private final int POOL_SIZE = 4;			//單個CPU的線程數
	
	private int portForShutdown = 8001;			//守護線程端口
	private ServerSocket serverSocketForShutdown = null;	//守護Socket
	private boolean isShutdown = false;			//服務器是否關閉
	
	private Thread shutDownThread = new Thread() {	//負責關閉服務器的線程
		public void start() {
			this.setDaemon(true);	//設置爲守護線程(後臺線程)
			super.start();
		}
		public void run() {
			while(!isShutdown) {
				Socket socketForShutdown = null;
				try {
					socketForShutdown = serverSocketForShutdown.accept();	//開啓監聽
					//獲取輸入流
					BufferedReader br = new BufferedReader(new InputStreamReader(socketForShutdown.getInputStream())); 
					String command = br.readLine();	//讀取一行字符
					if(command.equals("shutdown")) {	//判斷是否符合指定字符
						long beginTime = System.currentTimeMillis();	//開始計數
						//輸出流輸出字符
						socketForShutdown.getOutputStream().write("Server Shutdowning\r\n".getBytes());
						//服務器關閉
						isShutdown = true;
						//再也不向線程池添加新線程
						executorService.shutdown();
						//全部任務是否已完成
						while(!executorService.isTerminated()) {
							//設置線程池中任務的完成超時時間
							executorService.awaitTermination(30, TimeUnit.SECONDS);
						}
						//關閉服務器
						serverSocket.close();
						long endTime = System.currentTimeMillis();	//結束計數
						//輸出流輸出字符
						socketForShutdown.getOutputStream().write(("Server Shutdown\r\nTime:"+(endTime-beginTime)+"ms\r\n").getBytes());
						//關閉守護線程
						socketForShutdown.close();
						serverSocketForShutdown.close();
					}else {
						//不符合特定字符
						socketForShutdown.getOutputStream().write("Error".getBytes());
						socketForShutdown.close();
					}
				}catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	};
	public Server() throws IOException {
		//建立Socket
		serverSocket = new ServerSocket(port);
		serverSocket.setSoTimeout(60000);	//設置超時時間
		//建立守護Socket
		serverSocketForShutdown = new ServerSocket(portForShutdown);
		//建立線程池
		executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_SIZE);
		//運行守護線程
		shutDownThread.start();
		System.out.println("Server Up");
	}
	public void service() {
		while(!isShutdown) {
			Socket socket = null;
			try {
				socket = serverSocket.accept();
				socket.setSoTimeout(60000);
				executorService.execute(new Handler(socket));
			}catch (SocketTimeoutException e) {
				System.out.println("Client Timeout");
			}catch (RejectedExecutionException e) {
				try {
					if(socket != null) {
						socket.close();
					}
				}catch (IOException x) {
					return;
				}
			}catch (SocketException e) {
				if(e.getMessage().indexOf("socket closed") != -1) {
					return;
				}
			}catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	public static void main(String[] args) throws IOException {
		new Server().service();
	}
}
AdminClient.java
package Network_3;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

public class AdminClient {

	public static void main(String[] args) {
		Socket socket = null;
		try {
			socket = new Socket("localhost", 8001);
			OutputStream socketOut = socket.getOutputStream();
			socketOut.write("shutdown\r\n".getBytes());
			BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			String msg = null;
			while((msg = br.readLine()) != null) {
				System.out.println(msg);
			}
		}catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				if(socket != null) {
					socket.close();
				}
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}
相關文章
相關標籤/搜索