(三) 可中断套接字

当连接到一个套接字时,当前线程将会被阻塞知道建立连接或产生超时位置。同样地,当通过套接字读写数据时,当前线程也会被阻塞知道操作成功或产生超时为止。
在交互式的应用中,也许会考虑为用户提供一个功能,用以取消那些不会成功的连接。但是当线程因套接字长时间无法响应而发生阻塞时,无法通过调用interrupt来接触阻塞。
为了中断套接字操作,可以使用java.nio包提供的一个特性 SocketChannel 类。
例: 打开SocketChannel

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

通道(Channel)并没有与之相关联的流。实际上,它所拥有的read和write方法都是通过调用buffer对象来实现的。ReadableByteChannel接口和WritableByteChannel接口都继承了Channel。
如果不想处理缓存,可以使用Scanner类来读取信息,因为Scanner有一个带有ReadableByteChannel参数的构造器:
例:Scanner(ReadableByteChannel source)构造一个新的 Scanner,它生成的值是从指定信道扫描的。

    Scanner in = new Scanner(channel);

 
通过调用静态方法Channels.newOutputStream(),可以从通道中获取输出流。

    OutputStream outStream = Channels.newOutputStream(channel);

 

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

例:分别通过SocketChannel和InputStream读取
SocketChannel:

        messages.append("Blocking:\n");
        SocketChannel channel = SocketChannel.open(
                new InetSocketAddress("localhost", 8189));
        try{
            in = new Scanner(channel);
            while(!Thread.currentThread().isInterrupted()){
                if(in.hasNextLine()){
                    String line = in.nextLine();
                }
            }
        }finally{
            channel.close();
        }
 


InputStream:

        Socket socket = new Socket("localhost", 8189);
        try{
            in = new Scanner(socket.getInputStream());
            while(!Thread.currentThread().isInterrupted()){
                if(in.hasNextLine()){
                    String line = in.nextLine();
                }
            }
        }finally{
            socket.close();
        }
 

 

DEMO

 

import java.awt.EventQueue;

import javax.swing.JFrame;

public class InterruptibleSocketTest {
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable(){
			public void run(){
				JFrame frame = new InterruptibleSocketFrame();
				frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				frame.setVisible(true);
			}
		});
	}
}

 

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.channels.SocketChannel;
import java.util.Scanner;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class InterruptibleSocketFrame extends JFrame {
	
	public static final int WIDTH = 300;
	public static final int HEIGHT = 300;
	
	private Scanner in;
	private JButton interruptibleButton;
	private JButton blockingButton;
	private JButton cancelButton;
	private JTextArea messages;
	private TestServer server;
	private Thread connectThread;
	
	public InterruptibleSocketFrame(){
		setSize(WIDTH, HEIGHT);
		setTitle("InterruptibleSocketTest");
		
		JPanel northPanel = new JPanel();
		add(northPanel, BorderLayout.NORTH);
		
		messages = new JTextArea();
		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(Exception e){
							messages.append("\nInterruptibleSocketTest.connectInterruptible" + 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){
							e.printStackTrace();
							messages.append("\nInterruptibleSocketTest.connectInterruptible" + 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();
	}
	
	public void connectInterruptibly() throws IOException{
		messages.append("Blocking:\n");
		SocketChannel channel = SocketChannel.open(
				new InetSocketAddress("localhost", 8189));
		try{
			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{
			channel.close();
			EventQueue.invokeLater(new Runnable(){
				public void run(){
					messages.append("Channel closed\n");
					interruptibleButton.setEnabled(true);
					blockingButton.setEnabled(true);
				}
			});
		}
	}
	
	public void connectBlocking() throws IOException{
		messages.append("Blocking:\n");
		Socket socket = new Socket("localhost", 8189);
		try{
			in = new Scanner(socket.getInputStream());
			while(!Thread.currentThread().isInterrupted()){
				messages.append("Reading ");
				if(in.hasNextLine()){
					String line = in.nextLine();
					messages.append(line);
					messages.append("\n");
				}
			}
		}finally{
			socket.close();
			EventQueue.invokeLater(new Runnable(){
				public void run(){
					messages.append("Socket closed\n");
					interruptibleButton.setEnabled(true);
					blockingButton.setEnabled(true);
				}
			});
		}
	}
	
	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);
			}
		}
	}
	
	class TestServerHandler implements Runnable{
		
		private Socket incoming;
		private int counter;
		
		public TestServerHandler(Socket i){
			incoming = i;
		}
		
		public void run(){
			try{
				OutputStream outStream = incoming.getOutputStream();
				PrintWriter out = new PrintWriter(outStream, true);
				while(counter<100){
					counter++;
					if(counter <= 10){
						out.println(counter);
					}
					Thread.sleep(100);
					incoming.close();
					messages.append("Closing server\n");
				}
			}catch(Exception e){
				messages.append("\nTestServerHandler.run: " + e);
			}
		}
	}
}
 

 

你可能感兴趣的:(socket,SocketChannel)