客户端代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.SocketTimeoutException;
public class Client {
public static void main(String[] args) throws IOException {
// 本机请求与 host:port 相连接
String host = "192.168.1.198";
Integer port = 2019;
Socket client = new Socket(host, port);
// 10秒超时,避免盲目等待
client.setSoTimeout(10 * 1000);
// 从客户端终端输入信息
BufferedReader terminal = new BufferedReader(new InputStreamReader(System.in));
// 向服务器传送数据
PrintStream out = new PrintStream(client.getOutputStream());
// 从服务器获得信息
BufferedReader bf = new BufferedReader(new InputStreamReader(client.getInputStream()));
boolean flag = true;
while(flag){
// 从终端获取信息
System.out.print("client: ");
String input = terminal.readLine();
// 将信息传出
out.println(input);
// 发出信息后,等待服务器将回应
try{
// 在超时允许的时间内等待,客户端将会阻塞在这里,直到服务器回应或者超时
String message = bf.readLine();
System.out.println(message);
}catch (SocketTimeoutException e){
System.out.println("Time out, No response");
flag = false;
}
if("bye".equals(input)){
flag = false;
}
}
// 关闭资源流
out.close();
bf.close();
client.close();
}
}
单线程服务端代码
import org.apache.commons.lang3.StringUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 单线程 echo 服务器
*/
public class Server {
public static void main(String[] args) throws IOException {
// 开启端口2019作为echo服务器的监听端口
ServerSocket server = new ServerSocket(2019);
Socket client = null;
boolean flag = true;
PrintStream out;
BufferedReader bf;
try {
// 阻塞在此处,等待服务器连接
client = server.accept();
// 输出流,通过 out 将字节流输出到客户端
out = new PrintStream(client.getOutputStream());
// 输入流,通过 bf 获得客户端传送过来的字节流
bf = new BufferedReader(new InputStreamReader(client.getInputStream()));
while(flag) {
String message = bf.readLine();
if (StringUtils.isEmpty(message)) {
flag = false;
} else {
if ("bye".equals(message)) {
out.println("echo: bye");
flag = false;
} else {
out.println("echo: " + message);
}
}
}
out.close();
bf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
信息回复用的线程类
import org.apache.commons.lang3.StringUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
/**
* 处理客户端连接的线程
*/
public class EchoHandler extends Thread{
private Socket client;
private PrintStream out;
private BufferedReader bf;
public EchoHandler(Socket client){
this.client = client;
try{
out = new PrintStream(client.getOutputStream());
bf = new BufferedReader(new InputStreamReader(client.getInputStream()));
}catch (IOException e){
e.printStackTrace();
}
}
public void run(){
try{
while(true) {
String message = bf.readLine();
if (StringUtils.isEmpty(message)) {
break;
} else {
if ("bye".equals(message)) {
out.println("echo: bye");
break;
} else {
out.println("echo: " + message);
}
}
}
out.close();
bf.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
多线程服务器
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 基于多线程的 echo 服务器
*/
public class MultiThreadServer {
public static void main(String[] args) throws IOException {
// 开启端口2019作为echo服务器的监听端口
ServerSocket server = new ServerSocket(2019);
Socket client = null;
while(true){
System.out.println("Waiting for connection from client");
client = server.accept();
System.out.println("Client connected.");
new EchoHandler(client).start();
}
}
}
线程池服务器
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 基于线程池的 echo 服务器
*/
public class ThreadPoolServer {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(2019);
Socket client;
// 创建一个线程池,大小为 2
ExecutorService service = Executors.newFixedThreadPool(2);
while(true){
System.out.println("Waiting for connection from client");
client = server.accept();
System.out.println("Client connected");
//
service.execute(new EchoHandler(client));
}
}
}
关于线程池版本的测试:
一次开启三个客户端A、B、C,三者发出信息后会发现只有A、B会回复,而C则会因为超时而断开连接,因为C虽然建立了连接,但是服务端一次最多只能处理两个线程,又因为A、B没有断开连接(一直占用线程池的线程),所以无暇管理C。
如果在C发送信息过去的十秒内(超时时长),断开A或者B的连接,那么C的请求便可以得到处理(假设处理及时,能够在十秒内发送回客户端C)