Java Socket案例怎么基础通信

wen java案例 22

Java Socket案例:从零实现基础通信(附完整代码)

目录导读

  1. Socket通信原理:一文讲透TCP/IP与Socket的关系
  2. 环境准备:JDK版本与开发工具推荐
  3. 服务端实现:创建ServerSocket监听客户端连接
  4. 客户端实现:通过Socket连接服务端并发送消息
  5. 双向通信案例:实现服务端与客户端的实时对话
  6. 常见问题与解答:连接失败、端口占用、中文乱码等
  7. 总结与扩展:Socket在物联网、即时通讯中的应用

Socket通信原理:一文讲透TCP/IP与Socket的关系

问:Socket到底是个什么东西?它与TCP/IP协议栈有什么关系?
答:Socket是应用层与传输层之间的抽象接口,你可以把它理解为“网络通信的管道端点”,当两个程序要通过网络通信时,每一端都需要创建一个Socket,然后通过这个Socket发送或接收数据,在Java中,java.net.Socket代表客户端Socket,java.net.ServerSocket代表服务端监听Socket。

Java Socket案例怎么基础通信

TCP/IP协议栈分为应用层、传输层、网络层、数据链路层,Socket位于应用层与传输层之间,它封装了TCP的三次握手、数据分段、流量控制等复杂细节,开发者只需调用InputStreamOutputStream即可像操作本地文件一样进行网络读写。


环境准备:JDK版本与开发工具推荐

问:运行Socket程序需要什么环境?用IDE还是命令行?
答:

  • JDK版本:Java 8及以上即可,推荐Java 11(LTS长期支持版)。
  • 开发工具:IntelliJ IDEA或Eclipse,初学者可使用命令行编译运行:
    javac Server.java
    java Server
  • 注意事项:确保防火墙允许程序访问本地网络(通常本地回环地址127.0.0.1无限制)。

服务端实现:创建ServerSocket监听客户端连接

核心步骤:

  1. 绑定端口(例如8888)
  2. 调用accept()方法阻塞等待客户端连接
  3. 获取输入流读取客户端消息
  4. 获取输出流回复客户端

完整代码(Server.java)

import java.io.*;
import java.net.*;
public class Server {
    public static void main(String[] args) throws IOException {
        // 1. 创建ServerSocket,监听端口8888
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务端启动,等待客户端连接...");
        // 2. accept()是阻塞方法,直到有客户端连接
        Socket socket = serverSocket.accept();
        System.out.println("客户端已连接:" + socket.getInetAddress());
        // 3. 获取输入流,读取客户端数据
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(socket.getInputStream()));
        String message = reader.readLine();
        System.out.println("收到客户端消息:" + message);
        // 4. 获取输出流,向客户端发送响应
        PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
        writer.println("服务端已收到消息:" + message);
        // 5. 关闭资源
        reader.close();
        writer.close();
        socket.close();
        serverSocket.close();
    }
}

关键点说明

  • accept()会一直阻塞,直到有客户端接入。
  • PrintWriter的第二个参数true表示自动刷新缓冲区(每调用一次println就立即发送)。

客户端实现:通过Socket连接服务端并发送消息

问:客户端需要知道服务端的哪些信息?
答:IP地址(本地测试用127.0.0.1或localhost)和端口号(必须与服务端绑定的一致)。

完整代码(Client.java)

import java.io.*;
import java.net.*;
public class Client {
    public static void main(String[] args) throws IOException {
        // 1. 连接服务端(IP+端口)
        Socket socket = new Socket("127.0.0.1", 8888);
        System.out.println("已连接到服务端");
        // 2. 获取输出流,向服务端发送数据
        PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
        writer.println("Hello, Socket!");
        // 3. 获取输入流,读取服务端响应
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(socket.getInputStream()));
        String response = reader.readLine();
        System.out.println("服务端回复:" + response);
        // 4. 关闭资源
        reader.close();
        writer.close();
        socket.close();
    }
}

运行顺序:先运行Server.java,再运行Client.java
预期输出
服务端打印:收到客户端消息:Hello, Socket!
客户端打印:服务端回复:服务端已收到消息:Hello, Socket!


双向通信案例:实现服务端与客户端的实时对话

问:如何让服务端持续接收消息,而不是处理一次就退出?
答:使用while(true)循环,并为每个客户端连接创建独立线程。

优化版服务端(支持多客户端)

public class MultiThreadServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("多线程服务端启动...");
        while (true) {
            Socket socket = serverSocket.accept();
            // 每个客户端分配一个线程处理
            new Thread(new ClientHandler(socket)).start();
        }
    }
}
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()));
            PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
            String msg;
            while ((msg = reader.readLine()) != null) {
                System.out.println("收到:" + msg);
                writer.println("服务端回复:" + msg);
                if ("bye".equalsIgnoreCase(msg)) break;
            }
            System.out.println("客户端断开");
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端增加循环发送

// 在客户端main方法中
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
String input;
while ((input = console.readLine()) != null) {
    writer.println(input);
    String response = reader.readLine();
    System.out.println(response);
    if ("bye".equalsIgnoreCase(input)) break;
}

常见问题与解答

Q1:启动服务端时报错“Address already in use: bind”怎么办?
A:端口被占用,换一个端口(如9999),或使用netstat -ano | findstr 8888查看占用进程,同时确保服务端先启动。

Q2:客户端发送中文后服务端收到乱码?
A:统一编码,在创建InputStreamReader时指定字符集:

new InputStreamReader(socket.getInputStream(), "UTF-8");

客户端和服务端使用相同编码。

Q3:为什么客户端发送消息后服务端收不到?
A:最可能的原因是忘记调用flush()或关闭输出流,使用PrintWriter的自动刷新模式(第二个参数true)可解决,另一种可能是服务端readLine()要求消息必须换行结尾(\n)。

Q4:如何检测客户端是否断开?
A:调用socket.isConnected()不可靠,正确做法:从readLine()返回null时表示对方关闭了输出流,也可以发送心跳包(如每5秒发送一个特定字符串)。


总结与扩展:Socket在物联网、即时通讯中的应用

核心要点回顾

  • Socket是网络通信的基础,Java通过SocketServerSocket类简化了TCP编程。
  • 服务端需先绑定端口并调用accept()等待连接;客户端通过IP和端口发起连接。
  • 通信通过InputStream/OutputStream实现,读写需注意字符编码和流关闭。
  • 多线程处理可支持多个客户端同时连接。

进阶方向

  • NIO (Non-blocking IO):使用ServerSocketChannelSelector处理高并发。
  • WebSocket:基于HTTP升级协议,适合网页实时聊天。
  • 自定义协议:在Socket上层定义包头+包体的格式,解决粘包问题。

典型应用场景

  • 物联网设备数据采集(传感器定期发送数据到服务器)
  • 局域网即时通讯软件(飞鸽传书、QQ早期版本)
  • 分布式系统节点间心跳检测

如果你正在学习网络编程,建议先将本文基础案例亲手敲一遍并运行成功,再尝试增加文件传输、线程池、SSL加密等特性,掌握Socket原理后,后续学习Netty、MINA等高性能框架会事半功倍。

抱歉,评论功能暂时关闭!