- 浏览: 465362 次
- 性别:
- 来自: 西安
文章分类
最新评论
-
baiyingtao:
这些信息不太够,我们希望得到相关Keyword的段落,页码,区 ...
Lucene学习之使用Apache Tika进行文档内容抽取 -
王爱学志:
boolean isExist=false; 可以不用直接用 ...
去掉数组中重复元素的最高效算法 -
gavinj:
这些版本都太老了,这里贴出了xcode6系列下载地址,需要的朋 ...
xcode的各个版本的下载地址 -
最美的风景:
帮我大忙了
Android获得Location信息的方法 -
harvin:
yangwei0915 写道可以转载!谢谢。
android 中判断WiFi是否可用的可靠方法
在使用Java的API构建网络通信的应用时(尤其是基于移动的网络),有两种技术可供选择。第一种为直接使用Socket/Server Socket+输入输出流来构建,另外一种使用ServerSocketChannel+Selector。前者为阻塞式通信,需要服务端启动很多线程监听每一个客户端的Socket,通信效率低,且服务端容易受客户端的影响。比如当某个客户端当掉之后,服务的向这个客户端写数据的线程就会一直阻塞,直到写数据超时。所以我们在开发网络通信的应用时,首选后者。如下的代码实现了网络聊天/的功能,在加上语音或视频的录制功能又可实现网络的音频会议或视屏会议。网上和书上有很多类似的例子,但大多没有经过很好的测试,比如有一个客户端突然退出或者当掉,会影响服务端的运行。而我们的实际情况是要求服务端不应该受客户端的影响。
代码如下:
服务端:
package com.nio; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.channels.Channel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; /** * 非阻塞通信的服务端 * @author Alex * */ public class NioServer { private class NSServerThread extends Thread { private String ip; private int port; public NSServerThread(String ip, int port) { this.ip = ip; this.port = port; } public void run() { try { init(this.ip, this.port); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public void init(String ip, int port) throws IOException { // 用于检测所有Channel状态的Selector System.out.println("打开NioPTTServer 端口为:" + port); Selector selector = null; // 定义实现编码、解码的字符集对象 selector = Selector.open(); // 通过open方法来打开一个未绑定的ServerSocketChannel实例 ServerSocketChannel server = ServerSocketChannel.open(); // InetSocketAddress isa = new InetSocketAddress(ip, port); InetSocketAddress isa = new InetSocketAddress(ip, port); // 将该ServerSocketChannel绑定到指定IP地址 server.socket().bind(isa); // 设置ServerSocket以非阻塞方式工作 server.configureBlocking(false); // 将server注册到指定Selector对象 server.register(selector, SelectionKey.OP_ACCEPT); while (true) { int keys = selector.select(); // System.out.println("keys:"+keys); if (keys > 0) { // 依次处理selector上的每个已选择的SelectionKey // SelectionKey removeReadSk=null; try { for (SelectionKey sk : selector.selectedKeys()) { // 从selector上的已选择Key集中删除正在处理的SelectionKey selector.selectedKeys().remove(sk); // 如果sk对应的通道包含客户端的连接请求 if (sk.isAcceptable()) { // 调用accept方法接受连接,产生服务器端对应的SocketChannel SocketChannel sc = server.accept(); // 设置采用非阻塞模式 sc.configureBlocking(false); // 将该SocketChannel也注册到selector sc.register(selector, SelectionKey.OP_READ); // 将sk对应的Channel设置成准备接受其他请求 sk.interestOps(SelectionKey.OP_ACCEPT); } // 如果sk对应的通道有数据需要读取 if (sk.isReadable()) { // 获取该SelectionKey对应的Channel,该Channel中有可读的数据 SocketChannel sc = (SocketChannel) sk.channel(); // 定义准备执行读取数据的ByteBuffer ByteBuffer buff = ByteBuffer.allocate(1024); // 开始读取数据 int len = 0; try { if ((len = sc.read(buff)) > 0) { buff.flip();// 缓存 2指针复位 准备下次读取数据 System.out.println("读取数据:" + buff.array()); sk.interestOps(SelectionKey.OP_READ); }else{ System.out.println("没有数据读取,关闭通道"); sk.cancel(); if (sk.channel() != null) { sk.channel().close(); } } // 将sk对应的Channel设置成准备下一次读取 } // 如果捕捉到该sk对应的Channel出现了异常,即表明该Channel // 对应的Client出现了问题,所以从Selector中取消sk的注册 catch (IOException ex) { // 从Selector中删除指定的SelectionKey ex.printStackTrace(); sk.cancel(); if (sk.channel() != null) { sk.channel().close(); } System.out.println("关闭一个客户端"); } // 如果content的长度大于0,即聊天信息不为空 if (len > 0) { // 遍历该selector里注册的所有SelectKey SelectionKey writeKey = null; for (SelectionKey key : selector.keys()) { // 获取该key对应的Channel Channel targetChannel = key.channel(); // 如果该channel是SocketChannel对象 if (targetChannel instanceof SocketChannel) { // && key != sk) { // 将读到的内容写入该Channel中 ,返回到客户端 if (targetChannel instanceof SocketChannel && key != sk) { SocketChannel dest = null; try { // 将读到的内容写入该Channel中 ,返回到客户端 dest = (SocketChannel) targetChannel; System.out.println("写数据:" + buff.array()); dest.write(buff); } catch (Exception e) { // 写异常,关闭通道 e.printStackTrace(); if (dest != null) { dest.close(); } targetChannel.close(); writeKey = key; } } } } if (writeKey != null) { writeKey.cancel(); if (writeKey.channel() != null) { writeKey.channel().close(); } } } } } } catch (Exception e) { e.printStackTrace(); // selector.close(); // server.close(); // System.out.println("发生异常,重新打开端口"); // init(ip,port); // throw new RuntimeException(e); } } } } public static void main(String[] args) throws IOException { // System.out.println(InetAddress.getLocalHost().getHostAddress()); String host = InetAddress.getLocalHost().getHostAddress(); int port = 30000; new NioServer().new NSServerThread(host, port).start(); // new NServer().init(InetAddress.getLocalHost().getHostAddress(), // 30000); System.out.println("Nio服务端启动了,host:" + host); } }
客户端代码:
package com.nio; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.util.Scanner; /** * 非阻塞通信的服务端 * @author Alex * */ public class NioClient { public void init(String ip, int port) throws IOException { // 定义检测SocketChannel的Selector对象 Selector selector = null; // 定义处理编码和解码的字符集 //Charset charset = Charset.forName("UTF-8"); // 客户端SocketChannel SocketChannel sc = null; selector = Selector.open(); InetSocketAddress isa = new InetSocketAddress(ip, port); // 调用open静态方法创建连接到指定主机的SocketChannel sc = SocketChannel.open(isa); // 设置该sc以非阻塞方式工作 sc.configureBlocking(false); // 将SocketChannel对象注册到指定Selector sc.register(selector, SelectionKey.OP_READ); // 启动读取服务器端数据的线程------------ new ReadDataThread(selector).start(); new SendDataThread(sc,selector).start(); } private class SendDataThread extends Thread{ SocketChannel sc; Selector selector; public SendDataThread(SocketChannel sc,Selector selector){ this.sc=sc; this.selector=selector; } public void run(){ // 创建键盘输入流----------- Scanner scan = new Scanner(System.in); ByteBuffer byteBuf=ByteBuffer.allocate(152); File file=new File("D:/未命名2.jpg"); try{ InputStream in=new FileInputStream(file); int len=0; while (scan.hasNextLine()) { // 读取键盘输入 String line = scan.nextLine(); // 将键盘输入的内容输出到SocketChannel中 if("send".equals(line.trim())){ byte[] buf=new byte[152]; if((len=in.read(buf))>-1){ byteBuf.put(buf); byteBuf.flip(); sc.write(byteBuf); byteBuf.clear(); } byteBuf.put(buf); byteBuf.flip(); sc.write(byteBuf); byteBuf.clear(); }else if("quit".equals(line.trim())){ sc.close(); selector.selectedKeys().clear(); selector.close(); } //sc.write(charset.encode(line)); } }catch(Exception e){ e.printStackTrace(); } } } //读取服务器数据的----客户端监听线程 private class ReadDataThread extends Thread { Selector selector; public ReadDataThread(Selector selector) throws IOException { this.selector = selector; } public void run() { try { ByteBuffer buff = ByteBuffer.allocate(152); while (selector.select() > 0) { // 遍历每个有可用IO操作Channel对应的SelectionKey for (SelectionKey sk : selector.selectedKeys()) { // 删除正在处理的SelectionKey selector.selectedKeys().remove(sk); // 如果该SelectionKey对应的Channel中有可读的数据 if (sk.isReadable()) { // 使用NIO读取Channel中的数据 SocketChannel sc = (SocketChannel) sk.channel(); String content = ""; if (sc.read(buff) > 0) { sc.read(buff); buff.flip(); content = new String(buff.array());// charset.decode(buff); buff.clear(); } // 打印输出读取的内容 System.out.println("接收的数据:" + content); // 为下一次读取作准备 sk.interestOps(SelectionKey.OP_READ); } } } } catch (Exception ex) { ex.printStackTrace(); } } } public static void main(String[] args) throws IOException { new NioClient().init("192.168.42.128", 30000); } }
发表评论
-
redis 无法远程连接的问题
2017-05-18 09:42 1740打开redis.conf(windows为redis_63 ... -
通过maven向启动的tomcat中部署web应用
2017-05-03 11:09 5641.在tomcat的conf/tomcat-users.x ... -
启动Tomcat出现Unsupported major.minor version 51.0错误的解决方法
2016-01-28 11:19 1563此问题为java jdk和jre版本不同所致。猜测tomc ... -
关于Java的面试题
2015-06-17 11:40 847题目一 有一个在界面显示的字符串如下: &q ... -
ResultSet 调用getString 抛出NullPointException问题的解决
2014-10-16 18:10 4280在Java连接数据库时,有时候在ResultSet 调用g ... -
Lucene学习之构建简单通用的搜索查询接口
2013-11-02 10:42 1700在本篇博客中我们来构建一个简单而通用的搜索查询接口,在这个 ... -
Lucene学习之中文查询问题的解决
2013-10-31 10:32 1498在构建文档库之后, ... -
Lucene学习之构建简单的文档库
2013-10-31 09:19 1128在构建一个简单的文档库时,需要两个条件,第一,必须能抓取文 ... -
Lucene学习之使用Apache Tika进行文档内容抽取
2013-10-30 16:18 8640在上一篇关于Lucene的博客中,介绍了Lucene的入门 ... -
Lucene学习之Lucene入门暨中文文件搜索问题的解决
2013-10-30 11:28 1536Lucene是一款优秀的全文检索引擎的框架,提供了完整的查 ... -
java图片裁剪
2013-04-17 11:17 1035/** * 图片裁剪 * @param src ... -
按行读取字符文件
2013-04-04 16:20 859正确的写法是下面这样的: BufferedReader ... -
[转]让java程序在后台一直执行(例如putty关闭后后台程序继续运行)
2013-03-15 23:38 1840在linux系统下如何使一 ... -
Java的反射应用的场合
2011-07-22 16:41 1662Java从很早就提供了反射技术,我们在很多的程序中会使用到这种 ... -
线程的对象同步
2010-04-24 09:37 1155线程的对象同步也称为块同步,对象同步锁定的代码执行区 ... -
使用正则表达式分隔字符串
2010-04-14 16:23 1934在分隔一个字符串为数组时可采用String对象上的spilt方 ...
相关推荐
Java是一种广泛使用的面向对象的编程语言,以其跨平台、高效能和丰富的类库而闻名。在“基于java的高性能web代理程序”中,Java的技术基础扮演了核心角色。Java的多线程特性使得它非常适合构建能够处理大量并发请求...
Java AIO,全称为Asynchronous Input/Output,是Java NIO的一个扩展,它提供了一种非阻塞的I/O操作方式,使得开发者可以更高效地处理网络通信。T-io就是一个基于Java AIO实现的高性能、易用且稳定的网络编程框架。它...
1. **UDP协议**:UDP是一种无连接的、不可靠的传输层协议,它不保证数据包的顺序、完整性和可靠性,但具有低延迟和高效能的特点,适合实时通信或对速度要求较高的场景。 2. **Java网络编程基础**:在Java中,进行...
Java是一种广泛使用的面向对象的编程语言,以其跨平台、高性能、丰富的类库和高效能而闻名。"经典Java程序"这个标题暗示了我们可能会探讨一些Java编程中的基础概念、核心特性以及一些常见的经典示例。 Java的核心...
Java程序设计语言是软件设计师必备的核心技能之一,它以其跨平台、面向对象和高效能的特点在IT行业中占据了重要地位。本专题将深入探讨Java语言的关键概念、语法特性以及实际应用,帮助软件设计师提升编程能力。 一...
在计算机科学中,特别是在网络编程领域,多线程技术对于实现高效能的服务器应用至关重要。Java语言提供了丰富的多线程支持,使得开发者能够轻松地创建和管理多个执行线程,从而实现服务器对多个客户端请求的并发处理...
Java编程语言是全球范围内广泛应用的面向对象的编程语言,它以其跨平台、高效能和强大的类库而闻名。"Java学习资料大总结"这个压缩包很可能是为了帮助初学者或有经验的开发者系统地掌握Java的各项核心概念和技术。在...
在网络通信方面,可以利用NIO(非阻塞I/O)实现数据的多元化传输,批处理和缓存策略减少网络传输次数,从而降低ACK校验的开销。 JDK提供了一系列内置的监控工具,如JConsole、VisualVM和JMX,可以帮助开发者了解JVM...
在Android平台上进行网络通信时,UDP(User Datagram Protocol)是一种常用的选择,因为它具有无连接、低延迟和高效能的特点。本源码示例是针对Android应用程序设计的,它实现了UDP的双向通信,允许数据在客户端和...
1. 高性能:Dubbo基于NIO非阻塞I/O模型,实现了高并发处理能力,有效降低了系统资源的占用。 2. 服务治理:提供了服务注册、发现、调用、负载均衡、熔断、降级等全面的服务治理功能,确保了微服务的稳定性和可靠性。...
它通过非阻塞I/O(NIO)实现这一功能,使得在高并发场景下,系统资源能得到更有效的利用。 3. **请求与响应处理**:HttpCore提供了一套灵活的API来构建和解析HTTP请求与响应。开发者可以通过自定义请求头、设置请求...
高性能Server-Reactor模型是构建高效能网络服务的核心设计模式,尤其在Java领域中广泛应用。该模型主要用于解决C/S(客户端/服务器)架构中的高并发、低延迟问题,特别是在现代互联网应用如电子邮件、视频流媒体、...
Netty 是一个高性能、易用的网络通信框架,它基于 NIO(非阻塞I/O)设计,适用于构建高并发、低延迟的网络应用。Netty 提供了统一的 API,支持多种传输类型,如TCP、UDP,并且可以处理阻塞和非阻塞的连接。它内置了...
JDK 1.4引入的`java.nio`库提供了非阻塞I/O支持,这对于高并发的I/O操作非常有利,避免了大量线程创建的开销。在早期JDK版本中,可以寻找第三方库来支持非阻塞I/O。 3. **慎用异常** 异常处理应该仅用于错误情况...
在Web服务器领域,Tomcat以其轻量级、高效能和易于管理的特点,被广泛应用于各种规模的企业级应用开发和部署。 【描述】:在Web服务中,Tomcat扮演了核心角色,尤其是在Java开发中。作为Java标准版(Java SE)的一...
JRedis 内部使用非阻塞 I/O 模型,通常是 NIO (Java New I/O),以实现高效的网络通信。这意味着它能够在单个线程中处理多个连接,减少了线程切换的开销,提升了性能。同时,JRedis 还支持连接池,允许开发者管理多个...
在自定义RPC框架中,可以使用Java NIO库进行优化,实现更高效的I/O操作。 SOA(Service-Oriented Architecture)解决方案是一种面向服务的架构,强调将业务功能封装为独立的服务,通过标准接口进行交互。在自定义...
学员将学习如何使用File类进行文件操作,使用Socket编程实现网络通信,以及NIO的非阻塞特性,这对于构建高性能的服务器端应用至关重要。 在面向对象编程方面,训练营会深入探讨设计模式,如单例模式、工厂模式、...
FastCGI在Java中实现时,常常会与Socket服务端编程相结合,以创建高效能的Web服务。 在Java中,创建一个多线程TCP Socket服务器主要涉及以下知识点: 1. **Java套接字(Socket)**:Java提供Socket类来处理客户端...