赞
踩
关于回显服务器的概念在上篇博客中有解释
(1)TCP是面向字节流的,UDP是面向数据报的;
(2)TCP的服务器需要与操作系统内核建立连接,UDP不需要
(3)TCP是可靠传输,UDP是不可靠传输
(4)UDP效率较高,TCP相对UDP来说效率稍微逊;
代码如下:
public class TCPEchoServer {
private ServerSocket serverSocket = null;
//初始化serverSocket时需要绑定端口号
public TCPEchoServer(int port) throws IOException {
serverSocket = new ServerSocket(port);
}
}
进入主循环需要完成的事情:
- 与TCP建立连接
- 处理TCP连接
- 获取请求并解析
- 根据请求计算响应
- 将响应写回客户端
代码如下:
public void start() throws IOException { System.out.println("服务器启动"); while(true){ //负责与客户端交互 //与TCP建立连接 Socket clientSocket = serverSocket.accept(); //处理连接 processConnection(clientSocket); } } private void processConnection(Socket clientSocket) { System.out.printf("客户端上线 [%s:%d]",clientSocket.getInetAddress().toString(), clientSocket.getPort()); //TCP是面向字节流的,由于是回显服务器主要针对字符流文件,因此这里需要将字节流文件字符流化 try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream())) ){ while(true){ //获取请求并解析 //注意此处readLine()规定了读取是按照行读取的,同样写数据必须按行写,相当于自定义协议 String request = bufferedReader.readLine(); //根据请求计算响应 String response = process(request); //将响应写回客户端 //这里之所以加上换行符的原因是因为要按行写数据,需要遵循自定义协议 bufferedWriter.write(response+"\n"); //由于 bufferedWriter是带有缓冲区的,没有刷新的话数据就在缓冲区中,没有真正写到socket中 //需要手动刷新 bufferedWriter.flush(); //打印日志 System.out.printf("[%s:%d] req:%s resp:%s\n",clientSocket.getInetAddress().toString(), clientSocket.getPort(),request,response); } } catch (IOException e) { e.printStackTrace(); } } private String process(String request) { return request; }
完整代码如下:
import java.io.*; import java.net.ServerSocket; import java.net.Socket; /** * Author:ZouDouble * Description: * 天气:晴天 * 目标:Good Offer * Date 2021-01-05 17:20 */ public class TCPEchoServer { private ServerSocket serverSocket = null; //初始化serverSocket时需要绑定端口号 //serverSocket负责与客户端进行连接 public TCPEchoServer(int port) throws IOException { serverSocket = new ServerSocket(port); } public void start() throws IOException { System.out.println("服务器启动"); while(true){ //负责与客户端交互 //与TCP建立连接 Socket clientSocket = serverSocket.accept(); //处理连接 processConnection(clientSocket); } } private void processConnection(Socket clientSocket) { System.out.printf("客户端上线 [%s:%d]",clientSocket.getInetAddress().toString(), clientSocket.getPort()); //TCP是面向字节流的,由于是回显服务器主要针对字符流文件,因此这里需要将字节流文件字符流化 try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream())) ){ while(true){ //获取请求并解析 //注意此处readLine()规定了读取是按照行读取的,同样写数据必须按行写,相当于自定义协议 String request = bufferedReader.readLine(); //根据请求计算响应 String response = process(request); //将响应写回客户端 //这里之所以加上换行符的原因是因为要按行写数据,需要遵循自定义协议 bufferedWriter.write(response+"\n"); //由于 bufferedWriter是带有缓冲区的,没有刷新的话数据就在缓冲区中,没有真正写到socket中 //需要手动刷新 bufferedWriter.flush(); //打印日志 System.out.printf("[%s:%d] req:%s resp:%s\n",clientSocket.getInetAddress().toString(), clientSocket.getPort(),request,response); } } catch (IOException e) { e.printStackTrace(); } } private String process(String request) { return request; } public static void main(String[] args) throws IOException { TCPEchoServer server = new TCPEchoServer(9090); server.start(); } }
代码如下:
public class TCPEchoClientServer {
private Socket socket = null;
//注意:这里用的是Socket类,这里的serverIp和serverPort仅仅只是属性,初始化的时候并没有绑定端口号
//客户端初始化的时候不需要绑定端口号
public TCPEchoClientServer(String serverIp,int serverPort) throws IOException {
socket = new Socket(serverIp,serverPort);
}
进入主循环需要完成的事情:
- 读取客户请求并解析
- 构造请求发给服务器
- 从服务器读取响应
- 将响应写回客户端
代码如下:
public void start(){ System.out.println("客户端来咯"); Scanner scanner = new Scanner(System.in); try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())) ){ while(true){ //读取用户数据 System.out.println("输入请求->"); String request = scanner.nextLine(); if ("exit".equals(request)){ System.out.println("退出"); break; } //构造请求数据 bufferedWriter.write(request+"\n"); bufferedWriter.flush(); //从服务器读取响应 String response = bufferedReader.readLine(); //将响应写回客户端 System.out.println(response); } } catch (IOException e) { e.printStackTrace(); } }
完整代码如下:
import java.io.*; import java.net.Socket; import java.util.Scanner; /** * Author:ZouDouble * Description: * 天气:晴天 * 目标:Good Offer * Date 2021-01-05 17:42 */ public class TCPEchoClientServer { private Socket socket = null; //注意:这里用的是Socket类,这里的serverIp和serverPort仅仅只是属性,初始化的时候并没有绑定端口号 //客户端初始化的时候不需要绑定端口号 public TCPEchoClientServer(String serverIp,int serverPort) throws IOException { socket = new Socket(serverIp,serverPort); } public void start(){ System.out.println("客户端来咯"); Scanner scanner = new Scanner(System.in); try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())) ){ while(true){ //读取用户数据 System.out.println("输入请求->"); String request = scanner.nextLine(); if ("exit".equals(request)){ System.out.println("退出"); break; } //构造请求数据 bufferedWriter.write(request+"\n"); bufferedWriter.flush(); //从服务器读取响应 String response = bufferedReader.readLine(); //将响应写回客户端 System.out.println(response); } } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) throws IOException { TCPEchoClientServer client = new TCPEchoClientServer("127.0.0.1",9090); client.start(); } }
运行截图:
这样写出的代码有一个bug,它的建立连接和处理连接是串行执行的,代码中的while()循环是客户端下线才会触发,因此这个代码的局限性就是仅支持单用户使用,改进方法就是让它并发执行!如果使用多线程的话,由于多线程中也涉及到线程的创建与销毁,也是一些开销~最直接一步到位的方法就是利用线程池。接下来,我把多线程版本的和线程池版本的代码都放在下面,有需要的朋友可以看看!
import java.io.*; import java.net.ServerSocket; import java.net.Socket; /** * Author:ZouDouble * Description: * 天气:晴天 * 目标:Good Offer * Date 2021-01-05 18:02 */ public class TCPThreadEchoServer { private ServerSocket serverSocket = null; public TCPThreadEchoServer(int port) throws IOException { serverSocket = new ServerSocket(port); } public void start() throws IOException { System.out.println("服务器启动"); while(true){ Socket clientSocket = serverSocket.accept(); Thread thread = new Thread(){ @Override public void run() { processConnection(clientSocket); } }; thread.start(); } } private void processConnection(Socket clientSocket){ System.out.printf("[%s:%d]客户端上线~\n",clientSocket.getInetAddress().toString(), clientSocket.getPort()); try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream())) ) { while(true){ //1)读取请求并建立连接 String request = bufferedReader.readLine(); //2)根据请求计算响应 String response = process(request); //3)将响应写回客户端 bufferedWriter.write(response+"\n"); bufferedWriter.flush(); System.out.printf("[%s:%d] req:%s resp:%s\n",clientSocket.getInetAddress().toString(), clientSocket.getPort(),request,response); } } catch (IOException e) { System.out.printf("[%s:%d]客户端下线~\n",clientSocket.getInetAddress().toString(), clientSocket.getPort()); } } private String process(String request) { return request; } public static void main(String[] args) throws IOException { TCPThreadEchoServer server = new TCPThreadEchoServer(9090); server.start(); } }
import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Author:ZouDouble * Description: * 天气:晴天 * 目标:Good Offer * Date 2021-01-05 19:58 */ public class TCPEThreadPoolEchoServer { private ServerSocket serverSocket = null; public TCPEThreadPoolEchoServer(int port) throws IOException { serverSocket = new ServerSocket(port); } public void start() throws IOException { System.out.println("服务器启动"); ExecutorService executorService = Executors.newCachedThreadPool(); while(true){ Socket clientSocket = serverSocket.accept(); executorService.execute(new Runnable() { @Override public void run() { processConnection(clientSocket); } }); } } private void processConnection(Socket clientSocket){ System.out.printf("客户端上线[%s:%d]",clientSocket.getInetAddress().toString(), clientSocket.getPort()); try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream())) ) { while(true){ //1)接收请求并解析 String request = bufferedReader.readLine(); //2)根据请求计算响应 String response = process(request); //3)将响应写回客户端 bufferedWriter.write(response+"\n"); bufferedWriter.flush(); //打印日志 System.out.printf("[%s:%d] req:%s resp:%s\n",clientSocket.getInetAddress().toString(), clientSocket.getPort(),request,response); } } catch (IOException e) { System.out.printf("客户端下线[%s:%d]",clientSocket.getInetAddress().toString(), clientSocket.getPort()); } } private String process(String request){ return request; } public static void main(String[] args) throws IOException { TCPEThreadPoolEchoServer server = new TCPEThreadPoolEchoServer(9090); server.start(); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。