服务器的代码:
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.security.spec.RSAOtherPrimeInfo;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TcpEchoServer {
private ServerSocket serverSocket = null;
public TcpEchoServer(int port) throws IOException {
serverSocket = new ServerSocket(port);
}
public void start() throws IOException {
System.out.println("服务器启动!");
//采用线程池的目的是建立多个线程,使服务器可以同时处理多个客户端
ExecutorService service = Executors.newCachedThreadPool();
while(true){
//通过accept方法,把内核中已经建立好的连接拿到应用程序中
//建立连接的细节流程是内核自动完成的,应用程序只需要接收即可
Socket clientSocket = serverSocket.accept();
service.submit(new Runnable() {
@Override
public void run() {
try {
processConnection(clientSocket);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
//通过这个方法,来处理当前的连接
public void processConnection(Socket clientSocket) throws IOException {
//首先打印一个日志,说明有客户端已经连上了
System.out.printf("[%s:%d] 客户端上线 \n",clientSocket.getInetAddress(),clientSocket.getPort());
//TCP是面向字节流的,同时这里使用try方式,避免后续用完了流对象,忘记关闭
try(InputStream inputStream = clientSocket.getInputStream(); OutputStream outputStream = clientSocket.getOutputStream()){
//由于客户端发来的数据,可能是多条数据,针对多条数据,需要采用循环处理
while(true){
Scanner scanner = new Scanner(inputStream);
//没有下一条数据了,说明连接断开了,此时就应该结束循环
if(!scanner.hasNext()){
System.out.printf("[%s:%d] 客户端下线 \n",clientSocket.getInetAddress(),clientSocket.getPort());
break;
}
//1、读取请求并解析,此处使用next方式作为读取请求的方式,next的规则是,读到”空白符“就返回
String request = scanner.next();
//2、根据请求,计算响应
String response = process(request);
//3、把响应写回到客户端
//可以把String转成字节数组,写入到outputstream
//此处使用PrintWriter包裹outputstream,来写入字符串
PrintWriter printWriter = new PrintWriter(outputStream);
//此处的println不是打印到控制台了,而是写入到outputStream对应的流对象中,也就是写入到clientSocket里面
//自然这个数据也就通过网络发送出去了(发给客户端)
//此处的println带有\n,也是为了后续客户端这边可以使用scanner.next()来读取数据
printWriter.println(response);
//此处记得刷新缓冲区,如果不刷新,数据可能仍然在内存中,没有写入网卡
printWriter.flush();
//打印这次交互的内容
System.out.printf("[%s:%d] req=%s,resq=%s\n",clientSocket.getInetAddress(),clientSocket.getPort(),request,response);
}
}catch(IOException e){
e.printStackTrace();
}finally{
try{
//processConnection是在处理一个连接,这个方法执行完毕后,连接也就处理完了,所以此时要断开连接
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的同时,和服务器建立连接,此时就得告诉socket服务器在哪里
//建立连接的细节,不需要我们手动干预,是内核自动负责的
//当我们new这个对象的时候,操作系统内核,就开始进行“三次握手”具体细节,完成建立连接的工作
socket = new Socket(serverIp,serverPort);
}
public void start() throws IOException {
Scanner scanner = new Scanner(System.in);
try(InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream()){
PrintWriter writer = new PrintWriter(outputStream);
Scanner scannerNetwork = new Scanner(inputStream);
while(true){
System.out.print("->");
String request = scanner.next();
writer.println(request);
writer.flush();
String response = scannerNetwork.next();
System.out.println(response);
}
}catch(IOException e){
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
TcpEchoClient client = new TcpEchoClient("127.0.0.1",9090);
client.start();
}
}
运行结果截图: