1:EchoServer类
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class EchoServer1 {
private int port = 8000;
private ServerSocket serverSocket;
public EchoServer1() {
try {
serverSocket = new ServerSocket(port);
System.out.println("server starts");
} catch (IOException e) {
e.printStackTrace();
}
}
public void service() {
while(true) {
Socket socket = null;
try {
socket = serverSocket.accept(); //接收客户连接
Thread thread = new Thread(new Handler(socket)); //创建一个工作线程
thread.start(); //启动工作线程
} catch(IOException e) {
e.printStackTrace();
}
}
}
class Handler implements Runnable { //负责与单个客户端的通信
private Socket socket;
public Handler(Socket socket) {
this.socket = socket;
}
private PrintWriter getWriter(Socket socket) {
if(socket != null) {
try {
OutputStream outputSteam = socket.getOutputStream();
PrintWriter pw = new PrintWriter(outputSteam, true);
return pw;
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
private BufferedReader getReader(Socket socket) {
InputStream inputStream;
try {
inputStream = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
return br;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private String echo(String msg) {
return "Hello:" + msg;
}
@Override
public void run() {
try {
System.out.println("New Connection accepted,and the address is" + socket.getInetAddress() + ", and the port is " + socket.getLocalPort());
BufferedReader br = getReader(socket);
PrintWriter pw = getWriter(socket);
String msg = null;
while((msg = br.readLine()) != null) { //接收和发送数据,知道通信结束
System.out.println(msg);
pw.println(echo(msg));
if(msg.equals("bye")) {
break;
}
}
} catch(IOException e) {
e.printStackTrace();
} finally {
if(socket != null) {
try {
socket.close(); //断开连接
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class EchoClient {
private String localhost = "localhost";
private int port = 8000;
private Socket socket;
public EchoClient() throws UnknownHostException, IOException {
socket = new Socket(localhost, port);
}
private PrintWriter getWriter(Socket socket) throws IOException {
OutputStream socketOut = socket.getOutputStream();
return new PrintWriter(socketOut, true);
}
private BufferedReader getReader(Socket socket) throws IOException {
InputStream socketIn = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(socketIn));
return br;
}
public void talk() throws IOException {
try {
PrintWriter pw = getWriter(socket);
BufferedReader br = getReader(socket);
BufferedReader br_in = new BufferedReader(new InputStreamReader(System.in));
String msg = null;
while((msg = br_in.readLine()) != null) { //接收和发送数据,直到通信结束
pw.println(msg);
System.out.println(br.readLine());
if(msg.equals("bye")) {
break;
}
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if(socket != null) {
socket.close(); //断开连接
}
}
}
public static void main(String[] args) throws UnknownHostException, IOException {
new EchoClient().talk();
}
}
public static void main(String[] args) {new EchoServer1().service();}}
2:EchoClient类
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class EchoClient {
private String localhost = "localhost";
private int port = 8000;
private Socket socket;
public EchoClient() throws UnknownHostException, IOException {
socket = new Socket(localhost, port);
}
private PrintWriter getWriter(Socket socket) throws IOException {
OutputStream socketOut = socket.getOutputStream();
return new PrintWriter(socketOut, true);
}
private BufferedReader getReader(Socket socket) throws IOException {
InputStream socketIn = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(socketIn));
return br;
}
public void talk() throws IOException {
try {
PrintWriter pw = getWriter(socket);
BufferedReader br = getReader(socket);
BufferedReader br_in = new BufferedReader(new InputStreamReader(System.in));
String msg = null;
while((msg = br_in.readLine()) != null) { //接收和发送数据,直到通信结束
pw.println(msg);
System.out.println(br.readLine());
if(msg.equals("bye")) {
break;
}
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if(socket != null) {
socket.close(); //断开连接
}
}
}
public static void main(String[] args) throws UnknownHostException, IOException {
new EchoClient().talk();
}
}
3:
运行结果:EchoClient端:
EchoServer端:
4:结果分析
在以上程序中,服务器的主线程负责接收客户的连接,每次接收到一个客户连接,就会创建一个工作线程,由它负责与客户的通信。
Handler类实现了Runnable接口,它的run方法负责与单个客户通信,与客户通信结束后,就会断开连接,执行Handler的run方法的工作线程也会自然终止
5:实现方式的不足
*服务器创建和销毁工作线程的开销(包括所花费的时间和系统资源)很大
如果有很多客户端和服务器进行通信,那么有可能服务器为客户创建新线程的开销比实际与客户通信的开销还要大
*除了创建和销毁线程的开销外,活动的线程也消耗系统资源,每个线程本身都会占用一定的内存,如果同时有大量客户连接服务器,就必须创建大量的工作线程,
他们消耗了大量内存,可能会导致系统的空间不足。
*如果线程数目固定,并且每个线程都有很长的生命周期,那么线程切换也是相对固定的,也就是说,如果有大量的客户连接服务器,造成频繁的创建和销毁线程,
那么会导致频繁的切换线程,因为一个线程被销毁后,必然要把CPU转让给另一个已经就绪的线程,该线程获得运行的机会,在这种情况下,线程之间的切换不在遵循系统的固定切换周期,切换线程的开销甚至比创建和销毁线程的开销还要大