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

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

时间:2024-08-23 11:57:48浏览次数:8  
标签:Java Socket 线程 客户端 new 多线程 连接 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消息以及多线程模式有所帮助。如有任何疑问,请随时向我提问。如果您喜欢本文,欢迎点赞、收藏。

标签:Java,Socket,线程,客户端,new,多线程,连接,socket
From: https://blog.csdn.net/sbxjhvdddjdjd/article/details/141430796

相关文章

  • java基础--集合&学生管理系统
    1.ArrayList集合和数组的优势对比:长度可变添加数据的时候不需要考虑索引,默认将数据添加到末尾1.1ArrayList类概述什么是集合提供一种存储空间可变的存储模型,存储的数据容量可以发生改变ArrayList集合的特点长度可以变化,只能存储引用数据类型。泛型的使......
  • 【Java日志系列】Log4j2日志框架
    目录前言一、Log4j2简介与特征二、快速入门 三、SLF4j+Log4j2组合四、配置文件五、异步日志1.AsyncAppender方式2.AsyncLogger方式总结前言 在当今的软件开发领域中,日志记录是调试、监控和审计应用程序不可或缺的一部分。高效的日志记录不仅能帮助开发者理......
  • Java语法-注释 如何创建与配置空项目
    Java语法注释注释是给人看的,与代码执行无关单行注释//单行注释多行注释/*多行注释*/文档注释(JavaDoc:)/***//***@DscriptionHelloWorld*//****ii.;9ABH,*SA39......
  • python socket编辑示例 UDP
    服务端:fromsocketimportsocket,AF_INET,SOCK_DGRAMrecv_socket=socket(AF_INET,SOCK_DGRAM)recv_socket.bind(('127.0.0.1',8888))whileTrue:data,addr=recv_socket.recvfrom(1024)#接收数据print('客户说:',data.decode('......
  • Java数据类型转换
    自动类型转化(隐式转换):容量小的数据类型可以自动转换为容量大的数据类型。由低字节向高字节的转换byte->short->char–>int->long->float->double1.整行隐式类型转换:bytenum1=10;intnum2=num1;//byte转换为intshortnum3=1000;intnum4=num3;//short转换......
  • 并发编程[3]_java线程的六种状态
    java线程状态1.操作系统进程的五种状态网上找了一张图:2.java线程的六种状态Thread类中getState()方法可以获取线程的状态,返回值是Thread类中的enum类型,取值有NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED六种状态。java的线程状态将阻塞状态细分为BLOCKED,WAITING......
  • Java查看对象头大小
    添加依赖<dependency><groupId>org.openjdk.jol</groupId><artifactId>jol-core</artifactId><version>0.17</version></dependency>查看对象头大小@Testvoidhe......
  • python socket编辑示例
    服务端代码:fromsocketimportsocket,AF_INET,SOCK_STREAM#1.创建socket对象AF_INET:用于internet之间的进程通信,SOCK_STREAM:表示TCP协议server_socket=socket(AF_INET,SOCK_STREAM)#2.绑定ip和端口号ip='127.0.0.1'port=8888server_socket.bind((ip,p......
  • 第一个Java程序HelloWorld
    编写第一个程序HelloWorld在任意文件夹中创建java文件例如新建一个文本文件(.txt),然后修改文件名和文件扩展名记得打开显示文件扩展名!!!在Notpad++或记事本中打开刚刚创建的java文件(hello.world)编写publicclasshello{ publicstaticvoidmain(String[]args){ System.ou......
  • Java学习笔记8-数据类型
    Java中主要有八种基本数据类型:byte、short、int、long、float、double、boolean、char。各种数据类型作用:1、byte:8位、有符号的以二进制补码表示的整数。min:-128(-2^7)。max:127(2^7-1)。default:0。对应包装类:Byte。2、short:16位、有符号的以二进制补码表示的整......