Java 套接字:您可以从一个线程发送并在另一个线程上接收吗?

Posted

技术标签:

【中文标题】Java 套接字:您可以从一个线程发送并在另一个线程上接收吗?【英文标题】:Java sockets: can you send from one thread and receive on another? 【发布时间】:2011-12-09 17:05:51 【问题描述】:

这可能是一个非常基本的问题,但我很难找到答案。

是否可以让一个线程写入 Socket 的输出流而另一个线程从 Socket 的输入流中读取?

编辑:这是一个与外部服务器对话的客户端应用程序。我不是想让这两个线程互相交谈。很抱歉有歧义。

【问题讨论】:

Java 与 C++,但仍然密切相关:***.com/questions/1182806/sockets-send-and-receive。在coderanch.com/t/207132/sockets/java/… 也可以进行一些额外的讨论。 【参考方案1】:

假设您的意思是线程使用同一个套接字与外部参与者而不是彼此通信,这很常见,因为您通常不想在等待从套接字读取时阻塞。

线程1:

block on read
on recieve message - do something

线程2:

do things
on something happening - write to socket

如果您的意思是让两个线程在内部进行通信,您应该研究非套接字替代方案。

编辑:还要注意潜在的并发问题,因此请检查您使用的流是否是线程安全的。

【讨论】:

是的,我的意思是第一种情况:“线程使用同一个套接字与外部参与者通信,而不是相互通信” 您说“注意潜在的并发问题,因此请检查您使用的流是否是线程安全的”。你可以解释吗?同样,我正在与外部服务器交谈。如果线程 A 写入输出流,线程 B 读取输入流,是否存在并发问题? 不是在简单的情况下。但是,如果一个线程关闭连接和类似性质的事情,您将不得不处理会发生什么。【参考方案2】:

人们对您的问题感到困惑,这就是为什么一半人说“是的,但这不是两个线程应该相互通信的方式”,而另一个人将您的问题解释为“我希望一个线程始终写入套接字,另一个线程总是从套接字读取,所以我的程序可以同时发送和接收。”后面的解释意味着这两个线程不是使用套接字相互交换信息,而是另一台机器,这使得这不那么棘手。答案是肯定的。套接字是双向的,因此您可以同时发送和接收数据。这并不意味着您必须使用两个线程来执行此操作。

现在,这是非常不寻常的。在我研究套接字协议(POP、IMAP、HTTP 等)的所有时间里,我从来没有遇到过这种情况,或者换一种说法,我从来没有见过要求这种情况发生的协议.在某些时候,协议是同步的,其中一个端必须等待它发送更多信息或读取更多信息。我能想到的唯一情况是 RTMP、音频或视频流。但是,我认为其中大多数使用某种形式的非阻塞 IO,因此可以模拟同时通信。

这是您可能要考虑的下一件事情。当您处理来自套接字的消息时,您可能会在阻塞之前检查套接字的数据。如果它在那里读入,如果你有数据要写检查,看看你是否可以在没有阻塞的情况下写,然后写它。或者使用非阻塞 IO 套接字。这样,您只有一个线程读取/写入套接字,并且读取/写入之间的同步是不费吹灰之力的。对于线程,您将不得不使用锁定或信号量或其他东西在它们之间进行协调,这可能会导致死锁。

【讨论】:

【参考方案3】:

只要您有充分的理由以这种方式而不是通过其他线程通信技术进行通信,执行该操作就没有错。

这与考虑两个完全不同的应用程序侦听/写入同一个套接字的概念确实没有什么不同。

【讨论】:

【参考方案4】:

您可以让一个线程读取而另一个线程正在写入。 AFAIK 这可能是阻塞套接字的最常见用例。

可以让多个线程同时执行这两种操作,但这并不简单,而且每个线程很少需要多个线程。


你可以让两个线程在同一个进程中通信。这是我在单元测试中经常使用的东西,我在同一进程中有客户端和服务器组件。

您甚至可以使用一个线程从两端读取写入。 http://vanillajava.blogspot.com/2011/11/java-puzzle-single-threaded-client.html

替代方案可能是使用稍微快一点的管道流,或者 BlockingQueue(s) 或带有 ByteBuffers 或一堆或其他选项的 Exchanger。 ;)

【讨论】:

不抱歉(我只是按问题编辑)。我正在使用两个线程与外部服务器通信,而不是试图让两个线程相互通信。【参考方案5】:

换句话说,您想使用套接字将信息从一个线程发送到另一个线程?是的,这是可能的。我会强烈考虑一条不同的路线(他们可以互相传递一个参考,所以我认为这样会更好),但它应该可以工作。

在了解套接字的工作原理以及所涉及的问题时,将它们放在同一个应用程序中通常会大大简化事情,这是我强烈鼓励的。

但对于生产代码,我建议使用引用或线程安全队列或类似的东西。

编辑:回应您的评论和编辑:

是的。

有两种方法可以做到这一点:相同的线程,您可以在其中获取输入,然后对其做出反应,或者使用单独的线程,这样您就可以发送信息而不必接收它们。对于简单的程序,建议使用第一个,因为它最简单。但是对于最简单的协议之外的任何事情,您都需要第二个线程去同步输入和输出。

【讨论】:

不抱歉(我只是按问题编辑)。我正在使用两个线程与外部服务器通信,而不是试图让两个线程相互通信。【参考方案6】:

是的,但是您想使用什么流来创建“缓冲区”?它必须是 BlockingQueue 之类的东西

【讨论】:

【参考方案7】:

是的,你可以,套接字是双向的。 在实现你的协议时要小心。确保同步读取和写入调用,以及构建消息

【讨论】:

以上是关于Java 套接字:您可以从一个线程发送并在另一个线程上接收吗?的主要内容,如果未能解决你的问题,请参考以下文章

Serialport DataRecieved 线程在执行前结束

C++ 套接字 Send() 线程安全

将 Javascript 数组发送到控制器并在另一个 URL 中呈现视图结果

在另一个线程上接收的套接字上触发 EAGAIN

BOOST 如何在一个线程中发送信号并在另一个线程中执行相应的插槽?

Linux socket使用多线程发送