服务端
public class TCPServer {
public static final int SERVER_PORT = 9888;
public static void main(String[] args) throws IOException{
// 创建TCP的服务端
try(ServerSocket serverSocket = new ServerSocket(SERVER_PORT)) {
while(true){
// 建立连接
// 该方法时阻塞的,如果未连接,则会等待有人连接
Socket socket = serverSocket.accept();
SocketAddress socketAddress = socket.getRemoteSocketAddress(); // 对方的地址
int port = socket.getPort(); // 对方的端口
// 输入流
InputStream inputStream = socket.getInputStream();
// 输出流
OutputStream outputStream = socket.getOutputStream();
// 读取输入流
Scanner scanner = new Scanner(inputStream,"UTF-8");
// 写入
PrintWriter writer = new PrintWriter(
new OutputStreamWriter(outputStream,"UTF-8")
);
String request = scanner.nextLine(); // 也是阻塞的
String response = echoService(request);
writer.printf("%s\r\n",response);
writer.flush();
System.out.println("end");
socket.close();
}
} catch (IOException exception) {
exception.printStackTrace();
}
}
}
客户端
public class TCPClient {
private static final String SERVER_HOST = "127.0.0.1";
private static final int SERVER_PORT = TCPServer.SERVER_PORT;
public static void main(String[] args) throws IOException {
Scanner scanner = new Scanner(System.in);
try(Socket socket = new Socket(SERVER_HOST,SERVER_PORT)){
// 本地地址
SocketAddress socketAddress = socket.getLocalSocketAddress();
// 本地端口
int localPort = socket.getLocalPort();
// 服务器地址
SocketAddress socketAddress1 = socket.getRemoteSocketAddress();
// 都武器端口
int port = socket.getPort();
System.out.print("请输入请求: ");
String request = scanner.nextLine();
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
Scanner scan = new Scanner(inputStream,"UTF-8");
PrintWriter writer = new PrintWriter(
new OutputStreamWriter(outputStream,"UTF-8")
);
writer.printf("%S\r\n",request);
writer.flush();
String response = scan.nextLine();
System.out.println(response);
}
}
}
注意:①这是一个“短连接”客户端,就像打电话一样,有啥事打电话,如果有另外的事再打一个电话,“长连接”只需加一个while循环.
② 当一个同时运行两个客户端,第一个客户端不不发送请求,第二个客户端发送请求,第二个客户端会出现收不到来自服务端的响应,这是因为服务端里面的scanner,nextLine();也是一个阻塞,由于第一个客户端没有发送请求,服务端会一直等待第一个客户端发送请求,所以不会去处理第二个客户端的请求
分析:这是因为单线程的原因,所以,对服务端改造为多线程,利用线程池
将处理的事务拿出来作为单独的一个子线程,这里没有使用加锁关键字synchronized
子线程
public class TCPServerTask implements Runnable{
private final Socket socket;
public TCPServerTask(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try{ SocketAddress socketAddress = socket.getRemoteSocketAddress(); // 对方的地址
int port = socket.getPort(); // 对方的端口
// 输入流
InputStream inputStream = socket.getInputStream();
// 输出流
OutputStream outputStream = socket.getOutputStream();
// 读取输入流
Scanner scanner = new Scanner(inputStream,"UTF-8");
// 写入
PrintWriter writer = new PrintWriter(
new OutputStreamWriter(outputStream,"UTF-8")
);
String request = scanner.nextLine(); // 也是阻塞的
String response = echoService(request);
writer.printf("%s\r\n",response);
writer.flush();
System.out.println("end");
socket.close();
} catch (IOException e){
e.printStackTrace();
}
}
private String echoService(String request) {
return request;
}
}
主线程
public static void main(String[] args) throws IOException{
ExecutorService threadPool = Executors.newFixedThreadPool(8);
// 创建TCP的服务端
try(ServerSocket serverSocket = new ServerSocket(SERVER_PORT)) {
while(true){
// 建立连接
// 该方法时阻塞的,如果未连接,则会等待有人连接
Socket socket = serverSocket.accept();
Runnable task = new TCPServerTask(socket);
threadPool.execute(task);
}
} catch (IOException exception) {
exception.printStackTrace();
}
}
}