当前位置: 首页 > news >正文

TCP Socket API 讲解,以及回显服务器客户端的实现

文章目录

    • TCP
      • ServerSocket API
      • Socket API
    • TCP 客户端服务器的实现

TCP

ServerSocket API

ServerSocket 是创建TCP服务端 Socket 的 API。

serverSocket构造方法:

方法签名方法说明
ServerSocket(int port)创建一个服务端流套接字Socket,并绑定到指定端口

serverSocket方法:

方法签名方法说明
Socket accept()开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待
void close()关闭此套接字

Socket API

Socket 是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端 Socket。

不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。

Socket 构造方法:

方法签名方法说明
Socket (String host, int port)创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接

Socket 方法:

方法签名方法说明
InetAddress getInetAddress()返回套接字所连接的地址
InputStream getInputStream()返回此套接字的输入流
OutputStream getOutputStream()返回此套接字的输出流

TCP 客户端服务器的实现

因为 TCP 是面向连接的,所以TCP 服务器是需要多线程的,每个客户端连接都需要一个独立的线程来处理数据的收发和状态的维护,否则一个客户端的阻塞会影响其他客户端的正常通信。因此,TCP 服务器需要多线程来支持多个客户端的连接和通信

核心思路

  1. 服务器:

    • 首先给给这个服务器绑定一个端口号。(port:9090)

    • 启动服务器,利用 accept 方法建立与客户端的连接。

    • 建立线程池,后续操作在线程池中执行。

    • 接收客户端发送过来的请求。

    • 根据请求计算响应并发回,注意要添加一条“刷新缓冲区 (flush)”的操作。(回显服务器,响应值就是请求值)

    • 最后打印日志。

  2. 客户端:

    • 完成连接 TCP 服务器的操作。(ip: 127.0.0.1 , port: 9090)
    • 启动客户端,从控制台输入请求。
    • 把请求发送给服务器,同时还要加上刷新缓冲区 (flush) 的操作。
    • 最后读取服务器响应,并打印响应结果。
  3. 注意:

    因为 TCP 是字节流,所以利用 InputStream【Scanner】 和 OutputStream【PrintWriter】来读取或发送数据,由于InputStream 和 OutputStream 生命周期短,因此要及时 close(),这里我们用到 try-with-resources。

Java 打印流 PrintWriter 的介绍:PrintWriter 是 Java 中的一个字符类型的打印输出流,PrintWriter 可以将数据写入文件或其他输出流中,下面代码中用于 服务器向客户端发送数据/客户端向服务器发送数据

TCP 服务器的实现:

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.ExecutorService;
import java.util.concurrent.Executors;public class TcpEchoServer {private 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) {// 这个写法, 是能自动关闭, 也行. 实现 Closeable 接口就可以这么写.// 这么写会有其他问题. (结合后面讲第二个问题, 再说这个事)Socket clientSocket = serverSocket.accept();// 使用线程池, 来解决上述问题service.submit(new Runnable() {@Overridepublic void run() {processConnection(clientSocket);}});}}// 通过这个方法来处理一个连接的逻辑.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();// 日志, 打印当前的请求详情.System.out.printf("[%s:%d] req: %s, resp: %s\n", clientSocket.getInetAddress().toString(), clientSocket.getPort(), request, response);}} catch (IOException e) {e.printStackTrace();} finally {// 在 finally 中加上 close 操作, 确保当前 socket 被及时关闭!!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();}
}

TCP 客户端代码:

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 {// 这个 new 操作完成之后, 就完成了 tcp 连接的建立.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 printWriter = new PrintWriter(outputStream);//    使用 println 带上换行. 后续服务器读取请求, 就可以使用 scanner.next 来获取了printWriter.println(request);//    不要忘记 flush, 确保数据是真的发送出去了!!printWriter.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("127.0.0.1", 9090);client.start();}
}
http://www.lryc.cn/news/248842.html

相关文章:

  • 2023年掌控安全学院CTF暖冬杯——数据流分析
  • UE4 基础篇十四:自定义插件
  • QT QGraphicsItem 图元覆盖导致鼠标点击事件不能传递到被覆盖图元
  • proto语法学习笔记
  • python-nmap库使用教程(Nmap网络扫描器的Python接口)(功能:主机发现、端口扫描、操作系统识别等)
  • 什么是智慧工地?
  • 【古月居《ros入门21讲》学习笔记】08_发布者Publisher的编程实现
  • 沿着马可·波罗的足迹,看数字云南
  • 记录问题-使用@Validated报错Validation failed for argument [0]
  • three.js--立方体
  • App的测试,和传统软件测试有哪些区别?应该增加哪些方面的测试用例?
  • 改进LiteOS中物理内存分配算法(详细实验步骤+相关源码解读)
  • 洛谷100题DAY8
  • 2. OpenHarmony源码下载
  • flask app.config 用法
  • 【Vue】【uni-app】实现工单列表项详情页面
  • 安装vmware_esxi 超详细
  • Spring-Mybatis源码解析--手写代码实现Spring整合Mybatis
  • 5.2 Windows驱动开发:内核取KERNEL模块基址
  • 聊聊Go语言的注释
  • 皮肤警告,羊大师讲解身体与环境的默契
  • 使用NVM管理多个Nodejs版同时支持vue2、vue3
  • Android帝国之进程杀手--lmkd
  • 堆栈_队列实现栈
  • 好用的json处理工具He3 JSON
  • RabbitMQ消息模型之Routing-Direct
  • Harmony 应用开发之size 脚本
  • 商家门店小程序怎么做?门店小程序的优势和好处
  • 什么是灯塔工厂?灯塔工厂的作用?
  • 【GEO-AI】SAM-Geo库(segment-geospatial)入门教程