我有套接字客户端应用程序,在应用程序启动期间创建套接字(与服务器建立连接)并启动两个并行运行的线程。
Thread-1:使用read方法连续读取套接字(阻塞直到收到数据)
Thread-2:连续写入数据。
在编写套接字时,如果thread-2收到IO异常,则它会丢弃现有套接字并创建新套接字并开始通信。由于thread-2丢弃套接字,所以thread-1接收空指针异常。 我们有任何策略来处理这个
答案 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(服务器也是如此),但它可以更轻松地处理网络问题。它是一个反应堆,而不是一个反应堆。