`

(三) 可中断套接字

阅读更多

当连接到一个套接字时,当前线程将会被阻塞知道建立连接或产生超时位置。同样地,当通过套接字读写数据时,当前线程也会被阻塞知道操作成功或产生超时为止。
在交互式的应用中,也许会考虑为用户提供一个功能,用以取消那些不会成功的连接。但是当线程因套接字长时间无法响应而发生阻塞时,无法通过调用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);
			}
		}
	}
}
 

 

分享到:
评论

相关推荐

    异步套接字服务器与客户端

    异步套接字是网络编程中的一个重要概念,它在服务器端和客户端的通信中起着关键作用。在本文中,我们将深入探讨异步套接字的工作原理、优势以及如何在服务器端和客户端实现异步通信。 首先,让我们理解什么是异步套...

    流式套接字实现简单的客户端服务端通信过程

    流式套接字,也称为TCP(Transmission Control Protocol)套接字,是网络编程中常用的一种数据传输方式。TCP提供了一种面向连接、可靠的数据传输服务,确保了数据的顺序和完整性,适用于需要稳定、高效交换大量数据...

    套接字socket编程文档

    三、TCP套接字编程 1. 服务器端:首先创建套接字,然后绑定到特定端口,调用listen()开始监听。当有客户端连接时,accept()返回一个新套接字处理连接请求,服务器通过这个新套接字与客户端通信。 2. 客户端:创建套...

    套接字错误码1

    2. Socket error 10004 - 中断函数调用:该错误码表示套接字操作被中断。 3. Socket error 10013 - 权限拒绝:该错误码表示套接字操作没有足够的权限。 4. Socket error 10014 - 坏地址:该错误码表示套接字操作的...

    基于tcp的异步套接字客户端服务端通信

    - 异常情况下,如网络中断、内存不足,需确保正确关闭套接字,释放资源。 - 使用`closesocket()`(Windows)或`close()`(Unix-like)关闭套接字。 8. **性能优化** - 对于大量并发连接,优化I/O模型(如epoll的...

    套接字通信socket

    在计算机网络编程中,"套接字通信"是实现进程间通信(IPC)的重要机制,特别是在分布式系统和互联网应用中。套接字是操作系统提供的一个接口,允许应用程序通过它发送和接收数据。本文将深入探讨"套接字通信",特别...

    基于Java的Socket套接字编程 源代码

    在套接字编程中,异常处理是必不可少的。由于网络通信可能因各种原因中断,如网络故障、客户端断开连接等,因此需要捕获和处理IOException。 此外,关闭套接字和流是良好的编程习惯,可以避免资源泄露。通常,应当...

    MFC套接字编程

    5. 异常处理:在MFC套接字编程中,应捕获CAsyncSocket类的异常,如CErrors、CInternetException等,以处理网络错误和中断。 6. 客户端(Client)与服务器端(Server)的角色:客户端发起连接请求,通常执行发送数据...

    C语言套接字编程TCP连接

    在IT行业中,套接字编程是网络通信的基础,特别是在C语言环境下,它为开发者提供了低级别的接口来构建网络应用程序。TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,广泛应用于互联网上...

    流式套接字传输程序

    流式套接字编程是网络通信中的基础概念,主要用于实现数据的双向连续传输。在.NET框架和C++编程中,我们可以利用系统提供的API或者库来创建流式套接字(Stream Socket)应用,如本例中的"server.exe"服务器端和...

    完整的套接字数据库客户端

    在IT领域,套接字(Socket)是一种网络通信机制,它是应用程序通过网络与另一应用程序进行数据交换的一种方式。本文将详细解析"完整的套接字数据库客户端"这一主题,包括套接字的基本概念、数据库客户端的原理以及...

    易语言套接字源码例程.rar

    《易语言套接字源码例程》是一个针对易语言编程环境的套接字编程教程资源包。在本文中,我们将深入探讨易语言中的套接字编程基础,以及如何利用提供的源码例程进行学习和实践。 易语言,作为一款国内自主研发的中文...

    同步套接字服务器

    8. **错误处理**:在开发同步套接字服务器时,需要考虑各种异常情况,如网络中断、超时、资源耗尽等,确保服务器的健壮性。 9. **数据编码与解码**:在传输过程中,数据通常需要进行编码(如JSON、XML或二进制格式...

    MFC 套接字实现文件传输

    本主题将深入探讨如何使用MFC结合套接字技术实现文件传输功能,特别是带用户界面的程序。 首先,我们需要理解套接字(Socket)。套接字是网络通信的基础,它提供了一种进程间通信的接口,使得运行在不同计算机上的...

    套接字传输,VS2008服务器端

    7. **错误处理**:在套接字编程中,必须对可能出现的网络错误进行妥善处理,例如连接中断、数据传输错误等。这通常涉及检查返回值,使用`WSAGetLastError`获取错误代码,并根据情况采取相应的恢复策略。 8. **安全...

    套接字五元组

    【套接字五元组】是指在计算机网络通信中,用来唯一标识一个网络连接的五个元素的组合。这五个元素包括:协议(Protocol)、本地地址(Local Address)、本地端口(Local Port)、远程地址(Remote Address)和远程...

    TCP网口套接字聊天程序

    【TCP网口套接字聊天程序】是一种基于TCP协议实现的网络通信应用,它允许两台计算机之间进行类似QQ的实时聊天。在这个程序中,一台计算机作为服务器,提供监听和接收连接的服务,另一台计算机作为客户端,发起连接...

    聊天室代码 套接字 java

    【标题】:“聊天室代码 套接字 java” 【描述】:“java 聊天室代码 套接字很简单 适合于初级者” 在Java编程中,创建一个简单的聊天室涉及到网络通信的核心概念——套接字(Socket)。套接字是网络编程的基本...

    Winsock 教程_套接字试验

    **Winsock教程_套接字试验** Winsock是Windows操作系统中的网络编程接口,它提供了标准的Berkeley套接字API,使得程序员可以编写跨平台的网络应用程序。本教程旨在为初学者提供一个全面的Winsock学习框架,通过实践...

    套接字编程之大文件传输

    在IT领域,套接字编程是网络通信的基础,它允许应用程序通过网络发送和接收数据。本文将深入探讨如何使用C语言实现大文件的传输,主要涉及客户端与服务器之间的交互。 首先,我们需要理解套接字(Socket)的概念。...

Global site tag (gtag.js) - Google Analytics