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时,随机分配空闲端口。

无参数绑定端口

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

注意事项

死锁

建议:尽量减少任务之间的依赖。

系统资源不足

建议:根据系统性能设定线程数,回收机制。

并发错误

建议:使用成熟的线程技术。

线程泄露

建议:执行线程任务时,减少与用户的交互(使用超时机制)。

任务过载

建议:控制线程等待队列中的线程数。

关闭服务器

开放一个管理服务器端口,启动守护线程,供管理程序连接,当发送特定字符时,服务器停止向线程池添加任务并等待任务执行完毕或超时,关闭服务程序。

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

猜你喜欢

转载自www.cnblogs.com/lisztomania/p/12594222.html