客户端未向服务器发送消息 Java 套接字

Client side is not sending message to server Java Socket

我正在学习 java 中的套接字,但是当我是 运行 一个从客户端向服务器端发送消息的程序时,它没有显示消息。如果我在客户端输入一些文本,它不会显示在服务器端,但如果我输入 endProcess,它就会停止 运行。这意味着消息正在通过,只是没有显示。

我的 Client.java 代码在这里:

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

public class Client{
  Socket soc;
  DataInputStream dis;
  DataOutputStream dos;

  public Client(){
    try{
      soc = new Socket("(Address)",5000);
      System.out.println("Connection Established");
      dis = new DataInputStream(System.in);
      dos = new DataOutputStream(soc.getOutputStream());
      System.out.println("Streams connected");
    }catch(UnknownHostException u){
      System.out.println(u);
    }catch(IOException i){
      System.out.println(i);
    }

    String line = "";

    while(!line.equals("endConnection")){
      try{
        line = dis.readUTF();
        dos.writeUTF(line);
      }catch(IOException i){
        System.out.println(i);
      }
    }

    try {
        soc.close();
        dis.close();
        dos.close();
    } catch (Exception e) {
        System.out.println(e)    
    }
  }
  public static void main(String[] args) {
      new Client();
  }
}

这是我的 Server.java 代码:

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

public class Server {
    ServerSocket serSoc;
    Socket soc;
    DataInputStream dis;

    public Server(){
        try {
            serSoc = new ServerSocket(5000);

            System.out.println("Server Online");

            soc = serSoc.accept();
            System.out.println("Client Connected");

            dis = new DataInputStream(new BufferedInputStream(soc.getInputStream()));
        
            String line = "";
            System.out.println("Waiting for input...");
            while(!line.equals("endConnection")){
                line = dis.readUTF();
                System.out.println(line);
            }
            System.out.println("Client disconnected");

            soc.close();
            dis.close();
        } catch (Exception e) {
            System.out.println(e);
        }
        

    }
    public static void main(String[] args) {
        new Server();
    }
}

这里有很多问题。

双工协议问题

line = dis.readUTF();
dos.writeUTF(line);

这行不通; dis.readUTF() 行将阻塞(冻结),直到读取一行。问题是,有时你没有什么可发送的而你想阅读,而你没有什么可读的东西又想发送。实际上,您需要完全重新设计它;你需要 2 个线程。此时您会遇到多核问题,需要同步原语 and/or java.util.concurrent 类 用于在 2 个线程之间共享的所有数据。

或者,采用严格推或拉的模型(在任何给定时间,双方都已经知道谁可以发送,而如果另一方想发送,他们根本做不到。例如,每一方发送一个简单的'NOTHING TO DO'每秒发送消息,每次交换位置。当然,这是一个非常低效的算法。但可以在不涉及多线程的情况下编写。

刷新和关闭问题

dos.writeUTF(line);

这实际上不会发送任何内容,或者至少不保证会发送任何内容。要在 Internet 上发送任何数据,它会被包裹在一个具有大量开销的数据包中。所以,事情会被缓冲,直到有一个完整的数据包要发送。这意味着该行不执行任何操作。它只是填充一个缓冲区,没有数据包出去。您首先需要关闭或冲洗。 dos.flush() 也许会有帮助。这是个大问题,因为以后你会:

soc.close();
dis.close();
dos.close();

您首先关闭套接字,然后,关闭套接字。然后关闭流,这也将发送仍然停留在缓冲区中的任何内容,除非发送失败,因为套接字已经关闭。换句话说,您 .writeUTF()-ed 的行?它永远不会到达那里。您首先将其放入缓冲区,然后关闭套接字,然后发送缓冲区,因为套接字已经关闭,缓冲区将无法工作。

错误处理

} catch (Exception e) {
  System.out.println(e);
}

太可怕了。不要这样做。您的代码通过打印一些东西来对任何问题做出反应 并继续前进 。这意味着如果出现任何问题,客户端将开始发送无休止的异常跟踪队列并在运气好时锁定系统。您希望代码在出现问题时停止 运行。到目前为止,最简单的方法是将 throws IOException 粘贴在您的构造函数和 main 方法上,这是允许的。遥远的第二个最佳选择是将您的 'eh whatever' catch 块配置为 throw new RuntimeException("unhandled", e); 而不是 e.printStackTrace().

你所做的 (System.out.println(e);) 更糟糕 - 你正在丢弃非常有用的信息,例如堆栈跟踪和因果链。