多线程套接字通信中的场景

时间:2017-04-26 18:35:00

标签: java multithreading sockets

我有套接字客户端应用程序,在应用程序启动期间创建套接字(与服务器建立连接)并启动两个并行运行的线程。

Thread-1:使用read方法连续读取套接字(阻塞直到收到数据)

Thread-2:连续写入数据。

在编写套接字时,如果thread-2收到IO异常,则它会丢弃现有套接字并创建新套接字并开始通信。由于thread-2丢弃套接字,所以thread-1接收空指针异常。 我们有任何策略来处理这个

2 个答案:

答案 0 :(得分:1)

线程2需要在关闭之前关闭套接字以进行输入。这将导致线程接收和结束流,这将导致它关闭套接字并退出。然后线程2可以创建另一个套接字并启动另一个读取线程。

答案 1 :(得分:0)

您开始遇到与proactor风格的系统设计相关的问题。解决此问题需要两个线程之间进行一些通信。选择这种沟通方式就是它变得混乱的地方。它必须是阻止thread1尝试读取套接字的东西。我对Java不太满意,但在C中,这意味着使用信号。

我建议你避免使用信号,即使Java中存在相同的信号。

一个更好的选择是在调用select()(或任何Java等价物)时阻塞thread1,等待套接字和管道。 Thread2在想要关闭套接字时写入管道,thread1从select()返回,将响应写入管道中的thread2,并再次调用select(),但仅在管道上。 Thread2读取响应,关闭套接字,打开一个新的套接字,在管道上发送其他东西再次唤醒thread1,现在可以回到select(),但这次是在管道和新套接字上。这实现了thread1和thread2之间的执行会合; thread2可以关闭旧套接字并打开一个新套接字,因为它知道(通过管道通信)thread1何时不使用套接字。

这有些混乱。而且变得更像reactor设计模式。在这种情况下,也可以只使用一个线程使用select()来选择是否将套接字作为其执行的循环的一部分进行读取。这个单线程在可用时读取数据,而不是在希望数据到达时进行阻塞读取。如果套接字写入出现问题并且需要更换套接字,它就会这样做;没有其他线程可以与之同步。假设您的套接字连接到网络上的远程服务器(而不是同一台机器上的服务),以太网的速度仍然是主要的瓶颈;反应堆式系统并不慢。

通常,使用reactor系统样式处理网络故障要容易得多,因为您没有承诺执行其他线程知道不合适的操作的线程。不幸的是,大多数编程环境都是proactor,例如Windows,Boost ASIO,RabbitMQ等。在出现问题之前,Proactor系统很好,之后通常需要抛弃整个过程,因为它很容易变得非常复杂让程序员整理所有borked回调和异步IO。

如果可以,可以选择使用ZeroMQ。这要求您在任何地方使用ZeroMQ(服务器也是如此),但它可以更轻松地处理网络问题。它是一个反应堆,而不是一个反应堆。