• 可中断套接字(网络)


      当连接到一个套接字时,当前线程将会被阻塞直到建立连接或产生超时为止。同样地,当通过套接字读写数据时,当前线程也会被阻塞知道操作成功或产生超时为止。
      在交互式的应用中,也许会考虑为用户提供一个选项,用以取消那些不会成功的连接。但是当线程因套接字长时间无法响应而发生阻塞时,无法通过调用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("
    InterruptibleSocketTest.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("
    InterruptibleSocketTest.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:
    ");
          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("
    ");
                }
             }
          }
          finally
          {
             EventQueue.invokeLater(new Runnable()
             {
                public void run()
                {
                   messages.append("Channel closed
    ");
                   interruptibleButton.setEnabled(true);
                   blockingButton.setEnabled(true);
                }
             });
          }
       }
    
       /**
        * Connects to the test server, using blocking I/O
        */
       public void connectBlocking() throws IOException
       {
          messages.append("Blocking:
    ");
          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("
    ");
                }
             }
          }
          finally
          {
             EventQueue.invokeLater(new Runnable()
             {
                public void run()
                {
                   messages.append("Socket closed
    ");
                   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("
    TestServer.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
    ");
                }
             }
             catch (Exception e)
             {
                messages.append("
    TestServerHandler.run: " + e);
             }
          }
       }
    }

     

  • 相关阅读:
    PHP设计模式——迭代模式
    采用navicat导出表结构及数据insert声明
    [Angular] Protect The Session Id with https and http only
    [D3] Creating a D3 Force Layout in React
    [D3] Animate Chart Axis Transitions in D3 v4
    [D3] Animate with the General Update Pattern in D3 v4
    [Web Security] JSON Hijacking
    [Angular] Progress HTTP Events with 'HttpRequest'
    [RxJS] How To get the results of two HTTP requests made in sequence
    [RxJS] Avoid mulit post requests by using shareReplay()
  • 原文地址:https://www.cnblogs.com/gaopeng527/p/4528980.html
Copyright © 2020-2023  润新知