目录
1.实现一个TCP的回显服务
1.Sever Socket API
Sever Socket 是创建TCP服务端Socket的API
1.SeverSocket 构造方法
2.Sever Socket方法
2.Socket API
1.Socket的构造方法
2.Socket 方法
但是此服务器只能连接一个客户端,如果需要连接另一个客户端,只能让当前客户端断开连接,再连接另一个客户端
那么怎么实现让服务器可以处理多个客户端呢?
1.可以为每一个客户创建一个新的线程,让请求的处理在单独的子线程中去执行
但是这样如果有一万个客户端需要连接那就要创建一万个线程,会消耗非常大的系统资源,这时我们就可以通过线程池的方式进行优化,只给真正有需要的客户端建立连接
服务端代码:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.MessageFormat;
import java.util.Scanner;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class TCPEchoSever {
private ServerSocket server;
public TCPEchoSever(int port) throws IOException {
if (port < 1025 || port > 65535) {
throw new RuntimeException("端口号要在 1025 ~ 65535之间.");
}
//实例化SeverSocket对象
this.server = new ServerSocket(port);
}
public void start() throws IOException {
System.out.println("服务器已启动~~");
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(3,10,1, TimeUnit.SECONDS,new LinkedBlockingDeque<>(10));
// 循环接收客户端的连接
while (true) {
//接收客户端的数据
Socket clientSocket = server.accept();
// 提交任务到线程池中
poolExecutor.submit(() -> {
try {
processConnections(clientSocket);
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
//处理数据
private void processConnections(Socket clientSocket) throws IOException {
// 打印日志
String clientInfo = MessageFormat.format("[{0}:{1}] 客户端已上线", clientSocket.getInetAddress(),
clientSocket.getPort());
System.out.println(clientInfo);
try (InputStream inputStream = clientSocket.getInputStream();
OutputStream outputStream = clientSocket.getOutputStream()){
while (true) {
Scanner requestScanner = new Scanner(inputStream);
if (!requestScanner.hasNextLine()) {
// 日志
clientInfo = MessageFormat.format("[{0}:{1}] 客户端已下线.", clientSocket.getInetAddress(),
clientSocket.getPort());
System.out.println(clientInfo);
break;
}
String request = requestScanner.nextLine();
String response = process(request);
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.println(response);
printWriter.flush();
// 打印日志
clientInfo = MessageFormat.format("[{0}:{1}], request: {2}, response: {3}",
clientSocket.getInetAddress(), clientSocket.getPort(), request, response);
System.out.println(clientInfo);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
clientSocket.close();
}
}
private String process(String request) {
System.out.println("收到新消息:" + request);
Scanner scanner = new Scanner(System.in);
String response = scanner.nextLine();
return response;
}
public static void main(String[] args) throws IOException {
TCPEchoSever server = new TCPEchoSever(6666);
server.start();
}
}
客户端代码:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class TCPEchoClient {
private Socket clientSocket;
public TCPEchoClient (String serverIp, int serverPort) throws IOException, IOException {
this.clientSocket = new Socket(serverIp, serverPort);
}
public void start() throws IOException {
System.out.println("客户端已启动~~");
// 获取Socket中的输入输出流
try (InputStream inputStream = clientSocket.getInputStream();
OutputStream outputStream = clientSocket.getOutputStream()) {
// 循环处理用户的输入
while (true) {
System.out.println("->");
// 接收用户的输入内容
Scanner requestScanner = new Scanner(System.in);
String request = requestScanner.nextLine();
// 发送用户的请求
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.println(request);
// 强制刷新缓冲区
printWriter.flush();
// 接收服务器的响应
Scanner responseScanner = new Scanner(inputStream);
// 获取响应数据
String response = responseScanner.nextLine();
// 打印响应内容
System.out.println("接收到服务器的响应:" + response);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
clientSocket.close();
}
}
public static void main(String[] args) throws IOException {
TCPEchoClient client = new TCPEchoClient("127.0.0.1", 6666);
client.start();
}
}