Java 基础教程

Java 面向对象

Java 高级教程

Java 笔记

Java FAQ

java tcp长连接


在 Java 中实现 TCP 长连接有多种方式,下面我将为你详细介绍两种常见的方式:Socket 和 Netty。每种方式都将包括步骤流程和示例代码,并提供 Maven 和 Gradle 的依赖坐标。

使用普通的 Socket

步骤流程:

  1. 创建服务器端和客户端的 Socket 对象。
  2. 服务器端使用 ServerSocket 监听指定端口,客户端使用 Socket 连接服务器的 IP 和端口。
  3. 服务器端和客户端通过输入输出流进行通信。
  4. 保持连接的长短由你来控制,可以在服务器端或客户端决定何时关闭连接。

示例代码:

服务器端:

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

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(12345);
        System.out.println("Server is listening...");

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

            // Handle client communication using input/output streams
            BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);

            String message;
            while ((message = in.readLine()) != null) {
                System.out.println("Received: " + message);
                out.println("Server received: " + message);
            }

            clientSocket.close();
        }
    }
}

客户端:

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

public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("localhost", 12345);

        BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

        BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));
        String userInput;

        while ((userInput = consoleReader.readLine()) != null) {
            out.println(userInput);
            String response = in.readLine();
            System.out.println("Server response: " + response);
        }

        socket.close();
    }
}

依赖坐标:

这种方式不需要任何第三方库的依赖。

使用 Netty

步骤流程:

  1. 添加 Netty 依赖。
  2. 创建服务器端和客户端的引导(Bootstrap)。
  3. 配置引导,设置处理器来处理数据。
  4. 使用 Channel 进行通信,Netty 会管理底层的连接和线程池。
  5. 可以通过控制 Channel 的生命周期来管理连接的长短。

示例代码:

服务器端:

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class Server {
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                           .channel(NioServerSocketChannel.class)
                           .childHandler(new ChannelInitializer<SocketChannel>() {
                               @Override
                               protected void initChannel(SocketChannel ch) {
                                   ch.pipeline().addLast(new ServerHandler());
                               }
                           });

            ChannelFuture future = serverBootstrap.bind(12345).sync();
            System.out.println("Server is listening...");

            future.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

服务器处理器:

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class ServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ByteBuf buffer = (ByteBuf) msg;
        byte[] bytes = new byte[buffer.readableBytes()];
        buffer.readBytes(bytes);
        String message = new String(bytes);

        System.out.println("Received: " + message);

        // Send response
        ctx.writeAndFlush(ctx.alloc().buffer().writeBytes("Server received: ".getBytes()).writeBytes(bytes));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

客户端:

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                     .channel(NioSocketChannel.class)
                     .handler(new ChannelInitializer<SocketChannel>() {
                         @Override
                         protected void initChannel(SocketChannel ch) {
                             ch.pipeline().addLast(new ClientHandler());
                         }
                     });

            Channel channel = bootstrap.connect("localhost", 12345).sync().channel();

            Scanner scanner = new Scanner(System.in);
            while (true) {
                String userInput = scanner.nextLine();
                ByteBuf messageBuffer = Unpooled.copiedBuffer(userInput.getBytes());
                channel.writeAndFlush(messageBuffer);
            }
        } finally {
            group.shutdownGracefully();
        }
    }
}

客户端处理器:

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class ClientHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ByteBuf buffer = (ByteBuf) msg;
        byte[] bytes = new byte[buffer.readableBytes()];
        buffer.readBytes(bytes);
        String response = new String(bytes);
        System.out.println("Server response: " + response);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

依赖坐标:

在 Maven 中添加 Netty 的依赖:

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.68.Final</version>
</dependency>

在 Gradle 中添加 Netty 的依赖:

implementation 'io.netty:netty-all:4.1.68.Final'

这些示例代码和步骤流程应该能帮助你实现 TCP 长连接,无论是使用原生 Socket 还是 Netty。注意,这些代码仅作为示例,实际项目中可能需要根据需求进行更多的细节处理和错误处理。

Redis 连接命令用来做与 Redis 服务器之间的连接操作。 ...
本章节我们为大家介绍 Java 如何使用 使用 JDBC 连接 MySQL 数据库。 ...
###使用SocketSocket是Java提供的标准库,用于实现基于网络的通信。下面是使用Socket发送TCP报文的步骤:步骤流程:1. ...
以下是一些常见的数据库连接方式以及它们的详细步骤流程、Maven和Gradle依赖坐标以及示例代码。关闭连接:在完成操作后,关闭Result ...
对于每种方式,我也会提供适用的第三方库的Maven和Gradle依赖坐标。关闭连接和资源示例代码:Maven依赖:Gradle依赖:这里介绍 ...