You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

同一局域网下Java Socket客户端无法连接服务器:Ping通但Telnet失败的问题求助

同一局域网下Java Socket客户端无法连接服务器:Ping通但Telnet失败的问题求助

我最近在做一个Java项目,功能是客户端通过Socket给服务器传文件,服务器处理后返回结果。在我自己电脑上运行完全没问题,但把客户端放到朋友电脑上(同一局域网,已经把Client.java里的IP从localhost改成服务器的IP),就出现连接超时的情况。

客户端能ping通服务器,但用命令telnet <server_ip> <port>测试时连接失败。我们试过各种办法:关闭防火墙、给对应端口添加 inbound/outbound 规则、关闭杀毒软件,也确认了服务器确实在监听指定端口,但客户端这边还是连不上。有没有大佬能给点建议或者帮忙排查下问题?

服务器代码(server.java)

package server;

import common.ServerInterface;
import common.Task;
import common.Result;

import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;
import java.rmi.Naming;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.*;
import java.util.Stack;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class Server extends UnicastRemoteObject implements ServerInterface {
    private static final int PORT = 12345; // Listening Port

    protected Server() throws RemoteException {
        super();
    }

    private Stack<Task> taskStack = new Stack<>(); // Tasks
    private Map<String, Result> results = new HashMap<>(); // stores result as task ID

    @Override
    public synchronized Task getTask() throws RemoteException {
        if (!taskStack.isEmpty()) {
            return taskStack.pop(); // Retuns task if available
        }
        return null; // no task available
    }

    @Override
    public synchronized void returnResult(Result result, String taskId) throws RemoteException {
        // stores the result
        results.put(taskId, result);
        System.out.println("Results were received from Worker through RMI for the task " + taskId + ": " + result);
    }

    public void startSocketServer() {
        new Thread(() -> {
            try (ServerSocket serverSocket = new ServerSocket(PORT)) {
                System.out.println("Server is waiting for a connection on port " + PORT);

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

                    // Gérer la connexion client
                    new Thread(() -> handleClient(clientSocket)).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
    }

    private void handleClient(Socket clientSocket) {
        try (InputStream is = clientSocket.getInputStream();
             DataInputStream dis = new DataInputStream(is);
             OutputStream os = clientSocket.getOutputStream();
             DataOutputStream dos = new DataOutputStream(os)) {

            int fileCount = dis.readInt(); // read the number
            String taskId = UUID.randomUUID().toString(); // generate ID for task
            Task task = new Task(taskId); // create a new task

            int textFileCount = 0;

            for (int i = 0; i < fileCount; i++) {
                String fileName = dis.readUTF(); // read file name
                long fileSize = dis.readLong();  // read file size

                byte[] fileContent = new byte[(int) fileSize];
                dis.readFully(fileContent); // read all files on memory

                if (fileName.endsWith(".txt")) {
                    String fileContentStr = new String(fileContent); // convert matrices to string
                    if (textFileCount == 0) {
                        task.setDataFile1Content(fileContentStr);
                    } else if (textFileCount == 1) {
                        task.setDataFile2Content(fileContentStr);
                    }
                    textFileCount++;
                } else if (fileName.endsWith(".jar")) {
                    task.setOperationFileContent(fileContent); // stores in binary
                }
            }

            taskStack.push(task); // Add task
            System.out.println("Tak added : " + task);

            // wait for result
            while (!results.containsKey(taskId)) {
                Thread.sleep(1000);
            }

            // send result back to the client
            Result result = results.get(taskId);
            dos.writeUTF(result.getValue());
            System.out.println("Result sent to client : " + result);

            clientSocket.close();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        try {
            Server server = new Server();
            java.rmi.registry.LocateRegistry.createRegistry(1099);
            Naming.rebind("Server", server);
            System.out.println("Server RMI is ready");

            // run server
            server.startSocketServer();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

客户端代码(Client.java)

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

public class Client {
    public void sendTask(String serverAddress, String[] filePaths) {
        try (Socket socket = new Socket(serverAddress, 12345);
             OutputStream os = socket.getOutputStream();
             DataOutputStream dos = new DataOutputStream(os);
             InputStream is = socket.getInputStream();
             DataInputStream dis = new DataInputStream(is)) {

            // Send number of files
            dos.writeInt(filePaths.length);

            for (String filePath : filePaths) {
                File file = new File(filePath);
                if (!file.exists()) {
                    System.err.println("Error : File " + filePath + " does not exist !");
                    return;
                }

                // send file name
                dos.writeUTF(file.getName());

                // send file size
                dos.writeLong(file.length());

                // send file content
                try (FileInputStream fis = new FileInputStream(file)) {
                    byte[] buffer = new byte[1024];
                    int bytesRead;
                    while ((bytesRead = fis.read(buffer)) != -1) {
                        dos.write(buffer, 0, bytesRead);
                    }
                }
            }

            System.out.println("Task was sent to server");

            // receive final result
            String result = dis.readUTF();
            System.out.println("Results were received from the server : " + result);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Client client = new Client();
        String[] files = {
                "resources/data/A.txt",
                "resources/data/B.txt",
                "resources/operations/operation.jar"
        };
        client.sendTask("192.168.43.19", files);
    }
}

补充说明

我在自己电脑上运行服务器,朋友电脑运行客户端,预期是文件内容能成功发送,但实际连接超时。已经尝试关闭防火墙、添加端口规则,还是没解决。代码在localhost环境下完全正常,所以应该不是代码逻辑的问题。


可能的排查方向

  • 确认服务器绑定的IP地址:你的ServerSocket创建时用的是new ServerSocket(PORT),理论上会绑定到0.0.0.0(所有可用网卡),但可以在服务器上用netstat -ano | findstr 12345(Windows)或netstat -tulpn | grep 12345(Linux)检查,确认监听的是0.0.0.0:12345而不是127.0.0.1:12345——如果是后者,局域网其他机器肯定连不上。
  • 检查局域网IP是否正确:确认客户端用的服务器IP是服务器在局域网内的真实IPv4地址(比如服务器运行ipconfig/ifconfig得到的地址),有时候可能会误填成公网IP或者其他网卡的IP。
  • 路由器/交换机的限制:如果你们是通过路由器连接的同一局域网,有些路由器可能开启了AP隔离功能,会阻止局域网内设备之间的直接通信。可以登录路由器后台,看看有没有“AP隔离”“客户端隔离”这类选项,关掉试试。
  • 端口占用问题:虽然你确认服务器在运行端口,但可以再检查下服务器上有没有其他进程占用了12345端口,用上面的netstat命令就能看到。
  • 测试简化版连接:写一个最基础的Socket服务器和客户端,比如服务器只监听端口并打印连接信息,客户端只尝试连接,排除业务代码的干扰。如果这个简化版也连不上,那肯定是网络配置问题;如果能连上,再回头看你的业务代码有没有隐藏的问题。
  • 检查Windows Defender高级设置:有时候只关闭防火墙主开关没用,需要在“高级安全Windows Defender防火墙”里,确认针对12345端口的入站规则是允许所有远程IP,而不是只允许localhost。

备注:内容来源于stack exchange,提问作者ms maam

火山引擎 最新活动