使用Java NIO进行网络编程,看下服务端的例子

import java.io.IOException;
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.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; public class Server {
private static int PORT = 8000;
private static final long PAUSE_BETWEEEN_MSGS = 10; // millisecs
private static ByteBuffer echoBuffer = ByteBuffer.allocate(4);
private static ByteBuffer sendBuffer = ByteBuffer.allocate(256);
private static ConcurrentHashMap<Integer, SocketChannel> chm
= new ConcurrentHashMap<Integer, SocketChannel>();
private static int msg = 0; public static void main(String args[]) throws Exception {
Selector selector = Selector.open();
// Open a listener on each port, and register each one
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
InetSocketAddress address = new InetSocketAddress("localhost",PORT);
ssc.bind(address);
ssc.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Going to listen on " + PORT);
while (true){
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> it = selectedKeys.iterator(); System.out.println(selectedKeys.size());
while (it.hasNext()){
String msg = new String();
SelectionKey key = (SelectionKey) it.next();
if(key.isAcceptable()){
ServerSocketChannel sscNew = (ServerSocketChannel) key
.channel();
SocketChannel sc = sscNew.accept();
sc.configureBlocking(false);
// Add the new connection to the selector
sc.register(selector, SelectionKey.OP_READ);
// Add the socket channel to the list
chm.put(sc.hashCode(), sc);
it.remove();
}else if(key.isReadable()){
SocketChannel sc = (SocketChannel) key.channel();
int code = 0;
while ((code = sc.read(echoBuffer)) > 0) {
byte b[] = new byte[echoBuffer.position()];
echoBuffer.flip();
echoBuffer.get(b);
msg+=new String(b, "UTF-8");
}
// if(msg.length()>1)
// msg = msg.substring(0, msg.length()-2); //client关闭时,收到可读事件,code = -1
if (code == -1 ||
msg.toUpperCase().indexOf("BYE")>-1){
chm.remove(sc.hashCode());
sc.close();
} else {
//code=0,消息读完或者echoBuffer空间不够时,部分消息内容下一次select后收到
echoBuffer.clear();
}
System.out.println("msg: " + msg + " from: " + sc + "code: " + code );
it.remove(); //注册可写通知
sc.register(selector,SelectionKey.OP_WRITE);
}else if(key.isWritable()){
SocketChannel client = (SocketChannel) key.channel();
String sendTxt = "Message from Server";
sendBuffer.put(sendTxt.getBytes());
sendBuffer.flip();
int code = 0; //如果sendBuffer内容一次没有写完,会在下一次事件中处理吗?
while (client.write(sendBuffer) != 0){
}
if (code == -1 ){
chm.remove(client.hashCode());
client.close();
} else {
//code=0,消息写完
sendBuffer.clear();
}
it.remove();
System.out.println("Send message to client "); //在读通知里面注册为写事件,所以这里还需要注册为读,否则不在接受客户端消息
client.register(selector,SelectionKey.OP_READ);
}
}
Thread.sleep(5000);
}
}
}

使用windows telnet与服务端交互,在windows telnet中,需要使用send命令来按行发送消息,如下所示

一些说明:

1.select操作为阻塞操作,直至至少一个事件发生

2.server端只需注册accept事件

3.read、write为非阻塞操作,需要在代码中判断返回结果

4.read操作,如果接受的buffer大小不够,会在下一次select操作中接受

5.write操作呢?如果消息没有发完,怎么处理,下面这种循环么?

while (buffer.hasRemaining()){
socketChannel.write(buffer);
}

6.register会覆盖,所以在读写处理中交替注册

最新文章

  1. 百度地图API显示多个标注点带检索框
  2. UVA - 10375 Choose and divide[唯一分解定理]
  3. LAMP环境搭建
  4. [转]JDBC中日期时间的处理技巧
  5. ThreadPoolExecutor机制
  6. Bi-shoe and Phi-shoe(欧拉函数)
  7. 解决statusStrip控件上的项目不能靠右对齐的问题
  8. SqlServer日期(convert函数,getdate函数)
  9. Flask速成项目:Flask实现计算机资源的实时监控
  10. 将简单Excel表格显示到DataGridView中
  11. hihocoder 编程练习赛23
  12. Python自动化开发 - 函数式编程
  13. AI---训练集(train set) 验证集(validation set) 测试集(test set)
  14. Python socket应用
  15. mmap映射文件至内存( 实现 共享内存 与 文件的另类访问 )
  16. SOAP消息头的处理
  17. EXTJS 4:在renderer中如何控制一个CheckColumn的行为,如显示,只读等属性
  18. mfc 创建一个C++ 类
  19. Dummynet模拟高时延网络场景(Windows7)
  20. errno.h的数字对应的字符串错误

热门文章

  1. kali 系列学习01 - 安装、vmtools、ssh服务和共享文件夹
  2. tp5 删除图片以及文件
  3. On Starting My Blogging On CNBlogs
  4. python 中 try...finally... 的优雅实现
  5. 基于Koa2+mongoDB的后端博客框架
  6. Contest 984
  7. Forethought Future Cup - Final Round (Onsite Finalists Only) C. Thanos Nim 题解(博弈+思维)
  8. MySQL查询练习2
  9. 转载的一篇文章eclipse添加插件
  10. 一条 sql 的执行过程详解