【问题标题】:Android TCP send data trough one socketAndroid TCP 通过一个套接字发送数据
【发布时间】:2016-02-17 20:32:01
【问题描述】:

有以下代码:

public static PrintWriter outToServer;

private static Socket clientSocket;
    public static void register(InetAddress ip, int port, String name) {
    try {
        Utils.ip = ip;
        Utils.port = port;
        Utils.name = name;

        clientSocket = new Socket(Utils.ip, Utils.port);
        outToServer = new PrintWriter(clientSocket.getOutputStream(),true);

        send("reg:" + name);
}   catch (Exception e) {
        e.printStackTrace();
    }
 }
public static void send(String str) {
        outToServer.println(str);
}

我在应用程序启动时调用了一次register 方法。自从我使用send 方法将数据发送到服务器之后。问题是只有从register 调用的第一个send 才能从服务器正确接收。所有其他人都在发送,但没有收到(或者如果他们是,我看不到它们被显示)。我的服务器代码:

 public static void main(String argv[]) throws Exception {
  String clientSentence;
 ServerSocket welcomeSocket = new ServerSocket(9876);
 while (true) {
  Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient = new BufferedReader(
  new InputStreamReader(connectionSocket.getInputStream()));
clientSentence = inFromClient.readLine();
System.out.println("Received: " + clientSentence);
     }
  }

好的,但是当我从客户端尝试此代码时,它会通过发送更多流量来工作(我不希望那样)。

public static PrintWriter outToServer;

private static Socket clientSocket;
    public static void register(InetAddress ip, int port, String name) {
     try {
      Utils.ip = ip;
      Utils.port = port;
      Utils.name = name;

    send("reg:" + name);
}   catch (Exception e) {
    e.printStackTrace();
}
  }
  public static void send(final String str) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                clientSocket = new Socket(Utils.ip, Utils.port);
                outToServer = new PrintWriter(clientSocket.getOutputStream(), true);
                outToServer.println(str);
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    }).start();

我需要对此进行一些解释。
你可以从一个套接字有多个 OutPutStreams 吗?
为什么我在关闭 OutPutStream 并尝试在同一个套接字上打开一个新的时收到 socketClosed 异常。我现在只在send 中定义outToServer

    public static void send(final String str) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                PrintWriter outToServer = new PrintWriter(clientSocket.getOutputStream(), true);
                outToServer.println(str);
                outToServer.close();
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    }).start();
}

【问题讨论】:

  • 1) TCP/IP 缓冲输入和输出。如果要“立即”发送数据,则需要设置 TCP_NODELAY。 2) 关闭 Java 套接字关闭 TCP/IP 连接。因此出现“socketClosed”异常。 3) 强烈建议:阅读Beej's Guide to Network Programming。他讨论的概念直接适用于 Java 套接字。

标签: java android sockets tcp send


【解决方案1】:

你可以从一个套接字有多个输出流吗?

套接字只有一个输入流和一个输出流。

为什么当我关闭一个 OutputStream 并尝试在同一个套接字上打开一个新的套接字时出现 socketClosed 异常。

因为关闭套接字输入或输出流会关闭套接字,正如它在 Javadoc 中所说的那样。

NB 您发布的服务器代码永远不会关闭任何东西。您发布的客户端代码从不关闭任何内容,只发送一条消息。

NB 2 PrintWriter 会吞下异常,不应在网络上使用。使用 BufferedWriter。

【讨论】:

    【解决方案2】:

    您需要在套接字上设置TCP_NODELAY。默认设置是缓冲数据,直到它填满整个数据包。当缓冲区已满时,将发送一个数据包。但是,对于此协议,您希望立即发送数据,以便服务器能够响应。

    (https://stackoverflow.com/a/33658536/1172714)

    【讨论】:

    • 默认值是在有待处理的 ACK 时将数据缓冲一段有限的时间。不是“直到它填满整个数据包”。设置 TCP_NODELAY 不会治愈 SocketClosedException,这正是问题的真正意义所在。
    • 我忽略了 SocketClosedException。我看到他报发送但没有收到数据,看到没有设置TCP_NODELAY,这是不熟悉网络的人的通病
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-16
    • 1970-01-01
    • 2018-06-13
    • 2012-10-13
    • 2020-12-03
    • 1970-01-01
    • 2014-07-25
    相关资源
    最近更新 更多