一.过程:
1.建立连接(不是握手),虽然内核中的连接有很多,但是在应用程序中,要一个一个处理.
- 获取任务:使用ServerSocket.accept()方法,作用是把内核中的连接获取到应用程序中,这个过程类似于生产者消费者模型.
- 使用缓冲的时候,注意全缓冲和行缓冲.
4.注意关闭文件资源(client.socket.close()).
二.问题处理:
解决方法:使用多线程.
2.C10M问题:并发量太大.
解决方案:开源节流.
开源:创建线程.
节流:I/O多路复用,I/O多路转接.(java NIO)
三.代码实现:
1.回显服务器:
java
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
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 EchoTcpServer {
private ServerSocket serverSocket = null;
private ExecutorService service = Executors.newCachedThreadPool();
// 手动设置端口号
public EchoTcpServer(int port) throws IOException {
serverSocket = new ServerSocket(port);
}
// 启动服务器
public void start() throws IOException {
System.out.println("服务器启动");
while (true) {
Socket clientSocket = serverSocket.accept();
// processConnection(clientSocket);
// Thread thread = new Thread(() -> {
// try {
// processConnection(clientSocket);
// } catch (IOException e) {
// e.printStackTrace();
// }
// });
// thread.start();
service.submit(() -> {
try {
processConnection(clientSocket);
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
// 处理一个连接
private void processConnection(Socket clientSocket) throws IOException {
System.out.println("[" + clientSocket.getInetAddress().toString() + " " + clientSocket.getPort() + "]客户端已上线");
// 接下来进行读取请求,计算响应,返回响应三步走策略
try (InputStream inputStream = clientSocket.getInputStream();
OutputStream outputStream = clientSocket.getOutputStream()) {
Scanner scanner = new Scanner(inputStream);
// 一次连接可能会伴随多次请求与回应
while (true) {
// 1.读取请求
if (!scanner.hasNext()) {
// 读取结束
System.out.println("[" + clientSocket.getInetAddress().toString() + " " + clientSocket.getPort() + "]客户端已下线");
return;
}
// Tcp的数据是以字节流的形式发送的,这里默认发送文本文件.
String request = scanner.next();
// 2.处理请求
String response = process(request);
// 3.返回结果
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.println(response);
// 刷新
printWriter.flush();
System.out.println("[" + clientSocket.getInetAddress().toString() + " " + clientSocket.getPort() + "] 接收: "
+ request + " 回复:" + response);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭文件
clientSocket.close();
}
}
public String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
EchoTcpServer server = new EchoTcpServer(1999);
server.start();
}
}
2.回显用户端:
java
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 EchoTcpClient {
private Socket socket = null;
public EchoTcpClient(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) {
// 输入请求
System.out.println("->");
String request = scannerConsole.next();
// 发送请求
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.println(request);
printWriter.flush();
// 接收响应
Scanner scannerNetwork = new Scanner(inputStream);
String response = scannerNetwork.next();
// 打印响应
System.out.println(response);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
EchoTcpClient client = new EchoTcpClient("127.0.0.1", 1999);
client.start();
}
}
3.字典服务器:
java
import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;
public class DictionaryTcpServer extends EchoTcpServer{
private Map<String, String> dictionary = new HashMap<>();
public DictionaryTcpServer(int port) throws IOException {
super(port);
dictionary.put("I", "我");
dictionary.put("love", "爱");
dictionary.put("China", "中国");
}
@Override
public String process(String request) {
return dictionary.getOrDefault(request, "没找到");
}
public static void main(String[] args) throws IOException {
EchoTcpServer server = new DictionaryTcpServer(1999);
server.start();
}
}