在Java中实现通过TCP方式发送和接收Socket消息,包含在多线程状态下的实现

导言:

公司的代码,本来客户端client是前端的unity发送请求的,后面自己写的时候需要在本地进行测试,所以也用Java实现了前端,就写出来记录一下。

本文主要展示客户端client跟服务端server基础代码,里面的一些业务逻辑没有进行展示

正文

1.创建client端

首先我们需要创建一个client端进行发送消息,以下是实现的步骤:

  • 创建一个Socket对象,并指定Server端的IP地址和端口号。
  • 实现业务逻辑,发送需要传输的消息。
  • 使用Socket对象的getInputStream()方法获取输入流,可以读取Server端的响应消息。
  • 关闭Socket连接和相关资源。

2.创建server端

创建一个server端进行处理client发过来的请求,以下是实现的步骤:

  • 创建一个ServerSocket对象,并指定监听的端口号。
  • 使用accept()方法监听客户端的连接请求,并为每个连接创建一个新的线程进行处理。
  • 在线程中,使用Socket对象的getInputStream()方法获取输入流,可以读取客户端发送的消息。
  • 实现业务逻辑,处理收到的消息。
  • 使用Socket对象的getOutputStream()方法获取输出流,可以向客户端发送响应消息。
  • 关闭Socket连接和相关资源。

3.多线程模式

Server端实现中,为每个连接创建了一个新的线程来处理消息。这样可以并发地处理多个客户端的请求,提高通信效率。以下是实现的步骤:

  • 创建一个Runnable接口的实现类,实现run()方法。
  • 在run()方法中实现Server端的逻辑:监听客户端连接、接收消息、处理消息、发送响应。
  • 在Server端的主线程中,创建一个线程池(ThreadPoolExecutor)来管理线程的执行。
  • 使用线程池的execute()方法提交任务,每次有新的连接请求时,创建一个新的任务并执行。
  • 关闭线程池和相关资源。

代码举例

接收TCP消息

import java.io.*;
import java.net.*;

@Component
public class TcpServer {


    public void startServer() {
        try {
            ServerSocket serverSocket = new ServerSocket(1234);
            System.out.println("Server started. Waiting for client to connect...");

            while (true) {
                Socket clientSocket = serverSocket.accept();
                System.out.println("Client connected: " + clientSocket);

                // 创建线程处理客户端连接
                Thread thread = new Thread(new ClientHandler(clientSocket));
                thread.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static class ClientHandler implements Runnable {
        private Socket socket;

        public ClientHandler(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            try {
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

                String message = reader.readLine();
                System.out.println("Received message from client: " + message);

                // 处理消息(这里仅做回显)
                // 一般情况下是执行一些业务代码
                String response = "Server: " + message.toUpperCase() + "\n";

                writer.write(response);
                writer.flush();
                System.out.println("Sent response to client: " + response);

                // 关闭连接
                socket.close();
                System.out.println("Connection closed");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

同步发送TCP消息 

import java.io.*;
import java.net.*;

@Component
public class Client {
    public void startClient() {
        try (Socket socket = new Socket("localhost", 1234);
             BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
             BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"))) {

            System.out.println("Connected to server");

            String message = "Hello from client";
            writer.write(message);
            writer.newLine();
            writer.flush();
            System.out.println("Sent message to server: " + message);

            String response = reader.readLine();
            System.out.println("Received response from server: " + response);

            System.out.println("Connection closed");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

异步发送TCP消息 

import java.io.*;
import java.net.*;
import java.util.concurrent.*;

@COmponent
public class Client {
    public void startClient() {
        try {
            // localhost是server端的ip地址,可以通过Windows+R输入cmd,然后输入ipconfig查询到
            Socket socket = new Socket("localhost", 12345);
            System.out.println("Connected to server");

            ExecutorService executorService = Executors.newCachedThreadPool();

            Future<Void> sendFuture = executorService.submit(() -> {
                try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))) {
                    String message = "Hello from client";
                    writer.write(message);
                    writer.newLine();
                    writer.flush();
                    System.out.println("Sent message to server: " + message);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            });

            Future<String> receiveFuture = executorService.submit(() -> {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
                    String response = reader.readLine();
                    System.out.println("Received response from server: " + response);
                    return response;
                } catch (IOException e) {
                    e.printStackTrace();
                    return null;
                }
            });

            // 等待发送和接收完成
            sendFuture.get(5, TimeUnit.SECONDS); // 设置超时时间为5秒
            String response = receiveFuture.get(5, TimeUnit.SECONDS);

            // 关闭连接
            socket.close();
            executorService.shutdown();
            System.out.println("Connection closed");
        } catch (IOException | InterruptedException | ExecutionException | TimeoutException e) {
            e.printStackTrace();
        }
    }
}

在这个异步模式的示例中,我们使用了ExecutorService来创建一个线程池,并利用submit()方法异步地执行发送和接收任务。Future对象用于获取异步任务的结果。

通过这种方式,客户端可以并行地发送消息和接收响应,提高通信效率。请注意,在实际应用中,您可能需要根据具体需求对代码进行修改和调整以满足项目的要求。

在上述示例中,Server端监听1234端口,接受客户端的连接请求,并为每个连接创建一个新的线程进行处理。Client端连接到Server端,发送消息,并接收Server端的响应。Server端仅将客户端发来的消息转换为大写并回显。

请注意,在实际应用中,需要根据具体需求对代码进行修改和扩展,以满足更复杂的场景和功能要求。

 以上代码是在开发场景中,不能直接启动,可以将代码中方法名改为mian方法,也可以运用到实际项目中,然后在启动类上注入类,然后调用类的方法名。

代码分析

server端分析

  1. TcpServer 类

    • TcpServer 类负责启动服务器,并监听来自客户端的连接请求。
    • startServer 方法通过创建一个 ServerSocket 对象来监听端口,然后在一个无限循环中等待客户端连接。
    • 每当有客户端连接时,会创建一个新的 ClientHandler 线程来处理该客户端的通信。
    • main 方法用于启动服务器,创建 TcpServer 实例并调用 startServer 方法。
  2. ClientHandler 类

    • ClientHandler 类实现了 Runnable 接口,用于处理单个客户端的通信。
    • 在构造函数中接收一个 Socket 对象,该对象代表与客户端的连接。
    • 在 run 方法中,通过 BufferedReader 从客户端读取数据,并使用 BufferedWriter 向客户端发送响应。
    • 处理逻辑中,服务器简单地将客户端发送的消息转换为大写,并添加前缀 "Server: " 后发送回客户端。
    • 最后关闭与客户端的连接。
  3. 线程处理

    • 每个客户端连接都会在单独的 ClientHandler 线程中进行处理,这样可以同时处理多个客户端的请求。
    • 通过在 TcpServer 类的 startServer 方法中创建新线程来处理客户端连接,确保了服务器可以同时处理多个客户端请求。
  4. 异常处理

    • 代码中进行了基本的异常处理,捕获了可能发生的 IOException,并在出现异常时打印堆栈跟踪信息。
  5. 数据传输

    服务器从客户端读取一行数据,然后将处理后的响应发送回客户端,并在响应末尾添加换行符以确保数据完整性

client端分析

  1. Socket 连接和线程池:

    • 通过 Socket socket = new Socket("localhost", 12345); 建立到本地主机端口 12345 的 socket 连接。
    • 使用 ExecutorService executorService = Executors.newCachedThreadPool(); 创建了一个具有缓存的线程池,用于执行发送和接收消息的任务。
  2. 发送消息任务:

    • sendFuture 是一个 Future<Void> 对象,表示发送消息的任务。在该任务中,通过 BufferedWriter 向 socket 输出流写入消息。
  3. 接收响应任务:

    • receiveFuture 是一个 Future<String> 对象,表示接收响应的任务。在该任务中,通过 BufferedReader 从 socket 输入流读取响应消息。
  4. 等待任务完成和超时处理:

    • 通过 sendFuture.get(5, TimeUnit.SECONDS); 和 receiveFuture.get(5, TimeUnit.SECONDS); 等待发送和接收任务完成,并设置了 5 秒的超时时间。
  5. 关闭连接和线程池:

    • 在任务完成后,关闭了 socket 连接和线程池。
  6. 异常处理:

    • 使用 try-catch 块捕获了可能抛出的 IOExceptionInterruptedExceptionExecutionException 和 TimeoutException,并在捕获到异常时打印异常堆栈信息。

 结论

希望本文对您理解如何在Java中实现TCP方式发送和接收Socket消息以及多线程模式有所帮助。如有任何疑问,请随时向我提问。如果您喜欢本文,欢迎点赞、收藏。

  • 16
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值