import java.nio.channels.*;
import java.nio.charset.*;
import java.nio.*;
import java.util.*;
import java.io.*;
import java.net.*;
public class NBlockingServer {
int port = 8000;
int BUFFERSIZE = 1024;
Selector selector = null;
ServerSocketChannel serverChannel = null;
HashMap clientChannelMap = null; //用来存放每一个客户连接对应的套接字和通道
public NBlockingServer(int port) {
this.clientChannelMap = new HashMap();
this.port = port;
}
//throws IOException
public void initialize() {
//初始化,分别实例化一个选择器,一个服务器端可选择通道
try {
this.selector = Selector.open();
this.serverChannel = ServerSocketChannel.open();
this.serverChannel.configureBlocking(false);
InetAddress localhost = InetAddress.getLocalHost();
InetSocketAddress isa = new InetSocketAddress(localhost, this.port);
this.serverChannel.socket().bind(isa); //将该套接字绑定到服务器某一可用端口
}
catch (IOException ex) {
}
}
//结束时释放资源 throws IOException
public void finalize() {
try {
this.serverChannel.close();
this.selector.close();
}
catch (IOException ex) {
}
}
//监听端口,当通道准备好时进行相应操作 throws IOException, InterruptedException
public void portListening() {
//服务器端通道注册OP_ACCEPT事件
try {
SelectionKey acceptKey = this.serverChannel.register(this.selector,
SelectionKey.OP_ACCEPT);
//当有(已注册的事件)发生时,select()返回值将大于0
while (acceptKey.selector().select() > 0) {
//System.out.println("event happened");
//取得所有已经准备好的所有选择键
Set readyKeys = this.selector.selectedKeys();
//使用迭代器对选择键进行轮询
Iterator i = readyKeys.iterator();
while (i.hasNext()) {
SelectionKey key = (SelectionKey) i.next();
i.remove(); //删除当前将要处理的选择键
if (key.isAcceptable()) { //如果是有客户端连接请求
System.out.println("more client connect in!");
ServerSocketChannel nextReady = (ServerSocketChannel) key.channel();
SocketChannel sc = (SocketChannel) nextReady.accept();
//获取客户端套接字
//Socket s = nextReady.accept().socket();
Socket s = sc.socket();
//SocketChannel s = nextReady.accept();
//设置对应的通道为异步方式并注册感兴趣事件
//SocketChannel schannel=(SocketChannel)s.getChannel();
s.getChannel().configureBlocking(false);
//SelectionKey readWriteKey =s.getChannel().register(this.selector,SelectionKey.OP_READ |SelectionKey.OP_WRITE);
SelectionKey readWriteKey = s.getChannel().register(this.selector,
SelectionKey.OP_READ);
//将注册的事件与该套接字联系起来
readWriteKey.attach(s); //将给定的对象附加到此键。
//将当前建立连接的客户端套接字及对应的通道存放在哈希表//clientChannelMap中
this.clientChannelMap.put(s, new ClientChInstance(s.getChannel()));
}
else if (key.isReadable()) { //如果是通道读准备好事件
System.out.println("Readable");
//取得选择键对应的通道和套接字
SelectableChannel nextReady = (SelectableChannel) key.channel();
Socket socket = (Socket) key.attachment(); //// 检索当前的附加对象。
//处理该事件,处理方法已封装在类ClientChInstance中
this.readFromChannel(socket.getChannel(),
(ClientChInstance)this.
clientChannelMap.get(socket));
}
else if (key.isWritable()) { //如果是通道写准备好事件
System.out.println("writeable");
//取得套接字后处理,方法同上
Socket socket = (Socket) key.attachment(); // 检索当前的附加对象。
SocketChannel channel = (SocketChannel) socket.getChannel();
this.writeToChannel(channel, "This is from server!");
}
}
}
}
catch (ClosedChannelException ex) {
}
catch (IOException ex) {
}
}
//对通道的写操作
public void writeToChannel(SocketChannel channel, String message) {
try {
ByteBuffer buf = ByteBuffer.wrap(message.getBytes("gb2312"));
int nbytes = channel.write(buf);
}
catch (IOException ex) {
System.out.println("系统向客户端发送数据出错;");
}
}
//将读入字节缓冲的信息解码
public String decode(ByteBuffer byteBuffer) throws
CharacterCodingException {
Charset charset = Charset.forName("gb2312");
CharsetDecoder decoder = charset.newDecoder(); //为此 charset 构造新的解码器。
CharBuffer charBuffer = decoder.decode(byteBuffer); // 把单个输入字节缓冲区的剩余内容解码到新分配的字符缓冲区的便捷方法。
String result = charBuffer.toString(); //
return result;
}
//对通道的读操作throws IOException, InterruptedException
public void readFromChannel(SocketChannel channel,ClientChInstance clientInstance) {
try {
ByteBuffer byteBuffer = ByteBuffer.allocate(BUFFERSIZE);
int nbytes = channel.read(byteBuffer); //断开是出错
//System.out.println(nbytes);
byteBuffer.flip();
String result = this.decode(byteBuffer);
//当客户端发出”@exit”退出命令时,关闭其通道
if (result.indexOf("@exit") >= 0) {
channel.close();
System.out.println("客户端关闭");
}
else {
clientInstance.append(result.toString());
//读入一行完毕,执行相应操作
//if (result.indexOf("\n") >= 0) {
System.out.println("client input" + result);
clientInstance.execute();
//}
}
}
catch (IOException ex) {
try {
channel.close();
}
catch (IOException ex1) {
}
}
}
//该类封装了怎样对客户端的通道进行操作,具体实现可以通过重载execute()方法
public class ClientChInstance {
SocketChannel channel;
MessageData mdata; //业务处理模块
StringBuffer buffer = new StringBuffer();
public ClientChInstance(SocketChannel channel) {
this.channel = channel;
this.mdata= new MessageData();
}
public void execute() {
//String message = "AAA00100311111111000001100000200707161008220033 99999999hello,welcomd!this is 请求连接 first send.\n";
String info=buffer.toString();
String reinfo=mdata.isRigthData(info);
System.out.println("系统向客户端发送信息:"+reinfo);
if(reinfo!=null){
writeToChannel(this.channel, reinfo);
}
buffer = new StringBuffer();
}
//当一行没有结束时,将当前字窜置于缓冲尾
public void append(String values) {
buffer.append(values);
//mdata=new MessageData(this);
}
}
//主程序
public static void main(String[] args) {
NBlockingServer nbServer = new NBlockingServer(8000);
try {
nbServer.initialize();
}
catch (Exception e) {
e.printStackTrace();
System.exit( -1);
}
try {
nbServer.portListening();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
分享到:
相关推荐
Java NIO(非阻塞I/O)提供了这种能力,但本场景中我们讨论的是传统的阻塞式Socket。 三、ServerSocket的使用 1. 创建ServerSocket:通过`new ServerSocket(int port)`创建一个监听特定端口的服务器,其中port参数...
为了提高效率,可以采用多线程或者非阻塞I/O(如NIO,Java的新I/O库)来改进。但是,对于初学者来说,理解单线程阻塞模型是学习网络编程的基础,有助于深入理解Socket通信的工作原理。 此外,源码分析可以帮助我们...
总之,通过这个使用AIO实现的非阻塞socket通信项目,我们可以学习到如何利用Java AIO进行高效的网络编程,理解和实践异步I/O模型,这对于构建高性能、高并发的网络应用至关重要。通过实际操作,你可以更好地理解非...
Java非阻塞通信是现代Java开发中的一个重要概念,特别是在高并发和高性能的系统设计中。非阻塞通信允许程序在等待数据就绪时不会被挂起,而是继续执行其他任务,提高了系统的整体效率。这种技术主要应用于网络I/O...
在Java编程中,NIO(New ...总之,本项目通过Java NIO实现了非阻塞socket通信,有效地解决了高并发场景下的连接管理问题,提高了系统效率。对于学习和理解NIO以及如何构建基于NIO的网络应用,这是一个很好的实践案例。
书中提供了多个实用的案例,如简单的聊天室应用、文件传输服务等,这些案例不仅展示了Socket编程的基本原理,也涵盖了多线程、非阻塞I/O和安全通信等高级主题。通过动手实践,读者可以将理论知识转化为实际技能,更...
- 对于更复杂的聊天系统,可以考虑使用多线程处理多个客户端,或者使用NIO(非阻塞I/O)来提高性能。 - 进一步的话,可以集成WebSocket技术,实现持久化连接,提高用户体验。 总结来说,Java Socket实现的简易...
例如,使用非阻塞I/O(NIO)或者异步I/O(AIO)可以进一步提高服务器处理大量并发连接的能力。此外,负载均衡和故障恢复策略也是高可用服务器设计的重要组成部分。 总的来说,Java Socket开发高并发小型服务器涉及...
此外,还可以考虑使用NIO(非阻塞I/O)或异步I/O来提高性能和可扩展性。 记住,为了使客户端运行,服务器端也需要有相应的Socket服务,监听指定的端口并处理来自客户端的连接和数据。这通常涉及到创建一个`...
- 使用非阻塞I/O或异步I/O可以提高Socket通信的性能。Java的NIO(Non-blocking I/O)和C#的异步编程模型(如`async/await`关键字)都是不错的选择。 10. **测试与调试**: - 为确保通信正常,需要编写测试用例,...
- **NIO(非阻塞I/O)**:Java NIO库提供了非阻塞的Socket编程模型,适用于高并发场景,如`Selector`和`Channel`。 7. **实践应用** - **聊天应用**:基于Socket的简单聊天室,客户端发送消息到服务器,服务器...
### Java非阻塞式通信详解 #### 一、线程阻塞的概念与影响 线程阻塞是指在程序运行过程中,线程遇到某些条件而暂时停止执行的状态,这种状态下线程将不会消耗CPU资源,直到阻塞条件解除。在传统的Java网络编程中,...
在实际应用中,可能需要考虑多线程处理多个客户端连接,或者使用NIO(非阻塞I/O)以提高性能。此外,错误处理和异常捕获也是必不可少的部分,以确保程序的健壮性。 在提供的压缩包文件`socketServer`中,可能包含了...
Java.NET包的Socket通信不仅限于基础的TCP连接,还可以通过SocketChannel和Selector等NIO(非阻塞I/O)类进行高效率的并发通信。NIO允许一个线程同时处理多个连接,提高了服务器的性能和可扩展性。 总之,Java.NET...
在探讨如何使用Java NIO实现Socket通信之前,我们需要先理解NIO(Non-blocking I/O,非阻塞I/O)与传统阻塞I/O之间的区别。 **传统阻塞I/O模型**:在传统的Java IO编程中,当我们调用`read()`或`write()`方法时,...
服务器可以同时处理多个客户端的连接,这通常通过多线程或NIO(非阻塞I/O)来实现。 5. **编程结构**: 通常,Socket通信包括以下步骤: - 建立连接:客户端使用Socket的connect方法连接到服务器。 - 数据传输:...
Java Socket编程是网络编程中的重要组成部分,主要用于在两台计算机之间建立双向通信通道,实现数据的交换。在Java中,Socket类和ServerSocket类是进行网络通信的核心工具,它们提供了客户端与服务器之间的连接和...
在Java编程中,Socket是网络通信的基础,它允许两个应用程序通过TCP/IP协议进行数据传输。Socket连接分为两种类型:长连接和短连接。这两种连接方式各有特点,适用于不同的应用场景。 **1. 短连接(Short ...
这个简单的Hello World示例展示了NIO非阻塞Socket的基本工作原理,但在实际应用中,通常还需要处理更复杂的逻辑,如错误处理、心跳检测、连接管理等。理解并熟练运用Java NIO,可以帮助开发者构建出更加高效和可扩展...
在Java中,Socket通常被用来实现客户端-服务器架构,使得一个程序(服务器)可以提供服务,而另一个程序(客户端)则可以请求这些服务。下面我们将详细探讨Java Socket编程中的关键知识点。 1. **Socket类与...