【问题标题】:How does TCP chat program both send and receive data from the same thread?TCP 聊天程序如何从同一个线程发送和接收数据?
【发布时间】:2014-01-23 06:56:48
【问题描述】:

我注意到,在一些用 Java 编写的 TCP 聊天程序的示例代码中,从客户端读取字符串和向服务器发送字符串都发生在 main.h 中。

例如,这里有一个教程,我看不到输入线程和输出线程之间的区别...http://www.cise.ufl.edu/~amyles/tutorials/tcpchat/TCPChat.java

“BufferedReader 输入”和“PrintWriter 输出”都与同一线程中的 TCP 套接字一起使用。作为一个完全的新手,这让我感到困惑,因为以前,如果我有一些等待输入的东西,比如从 C 中获取字符函数的“getch()”,那么那个东西会阻塞线程(除非它是一个事件或异常)。通常,当我想象线程中的代码正在执行时,我想象它是逐行执行的,偶尔会出现异常和事件的执行跳转。但是写入流和读取流既不是异常也不是事件——我不知道如果主线程接收到输入字符串并且应该同时发送输出字符串会做什么。流本身是否实际上由其他线程或其他程序(如终端或操作系统)处理?

我对此感到很奇怪,所以我将聊天程序分成两个单独的线程以让我感觉更舒服 - 一个线程用于从 TCP 套接字接收字符串,另一个线程用于通过同一个套接字发送字符串。有人可以解释为什么我将输入和输出分成两个单独的线程的行为是完全没有必要的吗?在有人因缺乏研究和理解而将其记下之前,我尽我所能阅读了有关套接字的在线 Java 教程,并且我有读写流(终端和纯文本文件)的经验。

【问题讨论】:

  • 你能告诉我们你正在谈论的代码吗?出于您提到的原因,您应该为此需要单独的线程,除非您使用 select 之类的东西来等待输入。
  • 我看到创建了一个线程来处理 GUI,但我没有看到程序分成一个输入线程和另一个输出线程。
  • 我相信一切都在第 455 行:if (in.ready()) { 根据BufferedReader javadoc,该调用表明以下读取是否不会阻塞。这样I/O线程就不会阻塞了。
  • 您关于ready() 的说法是正确的。这是非常糟糕的技术:不要使用它。例如,如果发送方在没有行终止符的情况下发送数据,它仍然会阻塞。它似乎也在事件调度线程上执行网络操作。这是一部糟糕的作品。两个线程是更好的解决方案,或者使用 NIO 进行非阻塞 I/O。

标签: java c multithreading sockets tcp


【解决方案1】:
 case CONNECTED:
        try {
           // Send data
           if (toSend.length() != 0) {
              out.print(toSend); out.flush();
              toSend.setLength(0);
              changeStatusTS(NULL, true);
           }

           // Receive data
           if (in.ready()) {
              s = in.readLine();
              if ((s != null) &&  (s.length() != 0)) {
                 // Check if it is the end of a trasmission
                 if (s.equals(END_CHAT_SESSION)) {
                    changeStatusTS(DISCONNECTING, true);
                 }

                 // Otherwise, receive what text
                 else {
                    appendToChatBox("INCOMING: " + s + "\n");
                    changeStatusTS(NULL, true);
                 }
              }
           }
        }
        catch (IOException e) {
           cleanUp();
           changeStatusTS(DISCONNECTED, false);
        }
        break;

我从您提供的链接的“主程序”中获取了此代码 sn-p。 像你说的那样阻止线程继续的方法是 in.readLine();在继续之前,线程将等到从输入流中读取某些内容。我想指出 if 语句“ if(in.ready()) ” 通过在其中使用 if 语句,代码首先检查输入流是否有要读取的内容。否则,它会跳过它并继续。

【讨论】:

  • 请注意,如果发送方在没有行终止符的情况下发送数据,此代码仍然会阻塞。它似乎也在事件调度线程上执行网络操作。这是一项糟糕的工作。
猜你喜欢
  • 2012-04-22
  • 1970-01-01
  • 1970-01-01
  • 2018-08-28
  • 1970-01-01
  • 2011-09-13
  • 1970-01-01
  • 1970-01-01
  • 2019-11-20
相关资源
最近更新 更多