package network;
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.util.Scanner;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TcpEchoServer {
ServerSocket serverSocket = null;
// 此处不应该创建固定线程数目的线程池.
private ExecutorService service = Executors.newCachedThreadPool();
// 绑定端口号
public TcpEchoServer(int port) throws IOException {
serverSocket = new ServerSocket(port);
}
public void start() throws IOException {
System.out.println("服务器启动!");
while (true) {
Socket clientSocket = serverSocket.accept();
service.submit(new Runnable() {
@Override
public void run() {
processConnection(clientSocket);
}
});
/* Thread thread = new Thread(() -> {
processConnection(clientSocket);
});
thread.start();*/
}
}
// 通过这个方法来处理一个连接的逻辑.
private void processConnection(Socket clientSocket) {
System.out.printf("[%s:%d] 客户端上线!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
// 接下来就可以读取请求, 根据请求计算响应, 返回响应三步走了.
// Socket 对象内部包含了两个字节流对象, 可以把这俩字节流对象获取到, 完成后续的读写工作
try (InputStream inputStream = clientSocket.getInputStream();
OutputStream outputStream = clientSocket.getOutputStream()) {
while (true) {
// 1. 获取请求并解析, 使用 Scanner 来读取
Scanner scanner = new Scanner(inputStream);
if (!scanner.hasNext()) {
// 读取完毕, 客户端下线!
System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
break;
}
// 这个代码暗含一个约定, 客户端发过来的请求, 得是文本数据, 同时, 还得带有空白符作为分割. (比如换行这种)
String request = scanner.next();
// 2. 根据请求计算响应结果
String response = process(request);
// 3. 把响应结果写回客户端
// 把 OutputStream 使用 PrinterWriter 包裹一下, 方便进行发数据.
PrintWriter writer = new PrintWriter(outputStream);
// 使用 PrintWriter 的 println 方法, 把响应返回给客户端.
// 此处用 println, 而不是 print 就是为了在结尾加上 \n . 方便客户端读取响应, 使用 scanner.next 读取.
writer.println(response);
// 这里还需要加一个 "刷新缓冲区" 操作.
writer.flush();
// 4. 日志显示当前请求详情.
System.out.printf("[%s:%d] req: %s, resp: %s\n", clientSocket.getInetAddress().toString(), clientSocket.getPort(),
request, response);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
TcpEchoServer server = new TcpEchoServer(9090);
server.start();
}
}
package network;
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 socket = null;
// 要和服务器通信, 就需要先知道, 服务器所在的位置.
public TcpEchoClient(String serverIp, int serverPort) throws IOException {
socket = new Socket(serverIp, serverPort);
}
public void start() {
System.out.println("客户端启动!");
Scanner scannerConsole = new Scanner(System.in);
try (InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream()) {
while (true) {
// 1. 在控制台上输入字符串.
System.out.print("-> ");
String request = scannerConsole.next();
// 2. 将请求发送给服务器.
PrintWriter writer = new PrintWriter(outputStream);
writer.println(request);
writer.flush();
// 3. 从服务器读取响应.
Scanner scannerNetwork = new Scanner(inputStream);
String response = scannerNetwork.next();
// 4. 显示响应.
System.out.println(response);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
TcpEchoClient client = new TcpEchoClient("localHost", 9090);
client.start();
}
}
只需要继承自之前写的服务端, 然后重写父类 process 方法即可. 添加一些查询字典的逻辑.
package network;
import java.io.IOException;
import java.util.HashMap;
public class TcpDictServer extends TcpEchoServer {
private HashMap<String, String> dict = new HashMap<>();
public TcpDictServer(int port) throws IOException {
super(port);
dict.put("dog", "小狗");
dict.put("cat", "小猫");
dict.put("hello", "你好");
}
@Override
public String process(String request) {
return dict.getOrDefault(request, "查询的单词不存在!");
}
public static void main(String[] args) throws IOException {
TcpDictServer server = new TcpDictServer(9090);
server.start();
}
}
效果
✨ 本文记录了一个简单的 TCP 回显服务器代码.
✨ 想了解更多计算机网络的知识, 可以收藏一下本人的计算机网络学习专栏, 里面会持续更新本人的学习记录, 跟随我一起不断学习.
✨ 感谢你们的耐心阅读, 博主本人也是一名学生, 也还有需要很多学习的东西. 写这篇文章是以本人所学内容为基础, 日后也会不断更新自己的学习记录, 我们一起努力进步, 变得优秀, 小小菜鸟, 也能有大大梦想, 关注我, 一起学习.
再次感谢你们的阅读, 你们的鼓励是我创作的最大动力!!!!!