博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
可中断套接字(网络)
阅读量:6875 次
发布时间:2019-06-26

本文共 8006 字,大约阅读时间需要 26 分钟。

  当连接到一个套接字时,当前线程将会被阻塞直到建立连接或产生超时为止。同样地,当通过套接字读写数据时,当前线程也会被阻塞知道操作成功或产生超时为止。

  在交互式的应用中,也许会考虑为用户提供一个选项,用以取消那些不会成功的连接。但是当线程因套接字长时间无法响应而发生阻塞时,无法通过调用interrupt来解除阻塞。
  为了中断套接字操作,可以使用java.nio包提供的一个特性——SocketChannel 类。可以使用如下方法打开SocketChannel:

 

SocketChannel channel = SocketChannel.open(new InetSocketAddress(host, port));

 

  通道(channel)并没有与之相关联的流。实际上,它所拥有的read和write方法都是通过使用Buffer对象来实现的。ReadableByteChannel接口和WritableByteChannel接口都声明了这两个方法。

  如果不想处理缓冲区,可以使用Scanner类从SocketChannel中读取信息,因为Scanner有一个带有ReadableByteChannel参数的构造器。

Scanner in = new Scanner(channel);

  通过调用静态方法Channels.newOutputStream,可以将通道转换成输出流。

OutputStream outStream = Channels.newOutputStream(channel);

  上述操作都是必须做的。假设线程正在执行打开、读取或写入操作,此时如果线程发生中断,那么这些操作将不会陷入阻塞,而是以抛出异常的方式结束。

  下面的程序对比了可中断套接字和阻塞套接字:服务器将连续发送数字,并在每发送十个数字之后停滞一下。点击两个按钮中的任何一个,都会启动一个线程来连连接服务器并打印输出。第一个线程使用可中断套接字,而第二个线程使用阻塞套接字。如果在第一批的十个数字的读取过程中点击“Cancel”按钮,这两个线程都会中断。

  但是,在第一批十个数字之后,就只能中断第一个线程了,第二个线程将保持阻塞直到服务器最终关闭连接。

package interruptible;import java.awt.*;import java.awt.event.*;import java.util.*;import java.net.*;import java.io.*;import java.nio.channels.*;import javax.swing.*;/** * This program shows how to interrupt a socket channel. * @author Cay Horstmann * @version 1.03 2012-06-04 */public class InterruptibleSocketTest{   public static void main(String[] args)   {      EventQueue.invokeLater(new Runnable()         {            public void run()            {               JFrame frame = new InterruptibleSocketFrame();               frame.setTitle("InterruptibleSocketTest");               frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);               frame.setVisible(true);            }         });   }}class InterruptibleSocketFrame extends JFrame{   public static final int TEXT_ROWS = 20;   public static final int TEXT_COLUMNS = 60;   private Scanner in;   private JButton interruptibleButton;   private JButton blockingButton;   private JButton cancelButton;   private JTextArea messages;   private TestServer server;   private Thread connectThread;   public InterruptibleSocketFrame()   {      JPanel northPanel = new JPanel();      add(northPanel, BorderLayout.NORTH);      messages = new JTextArea(TEXT_ROWS, TEXT_COLUMNS);      add(new JScrollPane(messages));      interruptibleButton = new JButton("Interruptible");      blockingButton = new JButton("Blocking");      northPanel.add(interruptibleButton);      northPanel.add(blockingButton);      interruptibleButton.addActionListener(new ActionListener()         {            public void actionPerformed(ActionEvent event)            {               interruptibleButton.setEnabled(false);               blockingButton.setEnabled(false);               cancelButton.setEnabled(true);               connectThread = new Thread(new Runnable()                  {                     public void run()                     {                        try                        {                           connectInterruptibly();                        }                        catch (IOException e)                        {                           messages.append("\nInterruptibleSocketTest.connectInterruptibly: " + e);                        }                     }                  });               connectThread.start();            }         });      blockingButton.addActionListener(new ActionListener()         {            public void actionPerformed(ActionEvent event)            {               interruptibleButton.setEnabled(false);               blockingButton.setEnabled(false);               cancelButton.setEnabled(true);               connectThread = new Thread(new Runnable()                  {                     public void run()                     {                        try                        {                           connectBlocking();                        }                        catch (IOException e)                        {                           messages.append("\nInterruptibleSocketTest.connectBlocking: " + e);                        }                     }                  });               connectThread.start();            }         });      cancelButton = new JButton("Cancel");      cancelButton.setEnabled(false);      northPanel.add(cancelButton);      cancelButton.addActionListener(new ActionListener()         {            public void actionPerformed(ActionEvent event)            {               connectThread.interrupt();               cancelButton.setEnabled(false);            }         });      server = new TestServer();      new Thread(server).start();      pack();   }   /**    * Connects to the test server, using interruptible I/O    */   public void connectInterruptibly() throws IOException   {      messages.append("Interruptible:\n");      try (SocketChannel channel = SocketChannel.open(new InetSocketAddress("localhost", 8189)))      {         in = new Scanner(channel);         while (!Thread.currentThread().isInterrupted())         {            messages.append("Reading ");            if (in.hasNextLine())            {               String line = in.nextLine();               messages.append(line);               messages.append("\n");            }         }      }      finally      {         EventQueue.invokeLater(new Runnable()         {            public void run()            {               messages.append("Channel closed\n");               interruptibleButton.setEnabled(true);               blockingButton.setEnabled(true);            }         });      }   }   /**    * Connects to the test server, using blocking I/O    */   public void connectBlocking() throws IOException   {      messages.append("Blocking:\n");      try (Socket sock = new Socket("localhost", 8189))      {         in = new Scanner(sock.getInputStream());         while (!Thread.currentThread().isInterrupted())         {            messages.append("Reading ");            if (in.hasNextLine())            {               String line = in.nextLine();               messages.append(line);               messages.append("\n");            }         }      }      finally      {         EventQueue.invokeLater(new Runnable()         {            public void run()            {               messages.append("Socket closed\n");               interruptibleButton.setEnabled(true);               blockingButton.setEnabled(true);            }         });            }   }   /**    * A multithreaded server that listens to port 8189 and sends numbers to the client, simulating a    * hanging server after 10 numbers.    */   class TestServer implements Runnable   {      public void run()      {         try         {            ServerSocket s = new ServerSocket(8189);            while (true)            {               Socket incoming = s.accept();               Runnable r = new TestServerHandler(incoming);               Thread t = new Thread(r);               t.start();            }         }         catch (IOException e)         {            messages.append("\nTestServer.run: " + e);         }      }   }   /**    * This class handles the client input for one server socket connection.    */   class TestServerHandler implements Runnable   {      private Socket incoming;      private int counter;      /**       * Constructs a handler.       * @param i the incoming socket       */      public TestServerHandler(Socket i)      {         incoming = i;      }      public void run()      {         try          {            try            {               OutputStream outStream = incoming.getOutputStream();               PrintWriter out = new PrintWriter(outStream, true /* autoFlush */);               while (counter < 100)               {                  counter++;                  if (counter <= 10) out.println(counter);                  Thread.sleep(100);               }            }            finally            {               incoming.close();               messages.append("Closing server\n");            }         }         catch (Exception e)         {            messages.append("\nTestServerHandler.run: " + e);         }      }   }}

 

 

转载地址:http://ztofl.baihongyu.com/

你可能感兴趣的文章