返回信息流一个简单的nio通信例子:
服务器端:
public class serv{
public static void main(String[] args){
Selector sel = null;
ServerSocketChannel servChannal = null;
CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();
try {
//打开通道
servChannal = ServerSocketChannel.open();
//绑定地址
servChannal.socket().bind(new InetSocketAddress(12345));
//设为非阻塞模式
servChannal.configureBlocking(false);
//打开选择器
sel = Selector.open();
//通道指定要向哪个selector注册,通道所关注的事件是什么
servChannal.register(sel, SelectionKey.OP_ACCEPT);
System.out.println("服务器开始接收客户的链接!");
while(true){
//阻塞并等待已注册的事件发生,有事件发生时立即返回
sel.select();
//当一个通道注册到选择器上时,选择器创建一个选择键与此通道相关联
//我们通过选择键来获取我们刚注册的通道
Iterator<SelectionKey> iterator = sel.selectedKeys().iterator();
while(iterator.hasNext()){
SelectionKey key = iterator.next();
//一个key被处理完成后,就都被从就绪关键字(ready keys)列表中除去
iterator.remove();
//测试此键的通道是否已准备好接收新的套接字连接
if(key.isAcceptable()){
//获取我们刚注册的通道
ServerSocketChannel ser2 = (ServerSocketChannel)key.channel();
SocketChannel channel = ser2.accept();
channel.configureBlocking(false);
channel.register(sel, SelectionKey.OP_READ);
System.out.println("客户端:"
+channel.socket().getLocalAddress().getHostAddress()+":"
+channel.socket().getPort()+"连接上了");
channel.write(encoder.encode(CharBuffer.wrap("你已连接到服务器!")));
}
//测试此键的通道是否已准备好进行读取
else if(key.isReadable()){
SocketChannel channel = (SocketChannel)key.channel();
ByteBuffer buffer = ByteBuffer.allocate(50);
try {
channel.read(buffer);
} catch (Exception e) {
System.out.println("客户端:"
+ channel.socket().getInetAddress().getHostAddress() + ":"
+ channel.socket().getPort() + " 已断开连接");
channel.close();
continue;
}
//对该缓冲区作“翻回”操作,该方法将limit值置为当前位置,然后将当前位置指针position
//置为0,并丢弃已定义的书签。
buffer.flip();
String msg = decoder.decode(buffer).toString();
System.out.println("收到消息来自:"+channel.socket().getLocalAddress().getHostAddress()+":"
+channel.socket().getPort()+":"+msg);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
sel.close();
servChannal.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端:
public class client{
public static void main(String[] args){
clientThread clnt = new clientThread();
clnt.start();
InputStreamReader streamReader = new InputStreamReader(System.in);
BufferedReader reader = new BufferedReader(streamReader);
try {
String readline;
while((readline = reader.readLine()) != null){
if(readline.equalsIgnoreCase("bye")){
clnt.close();
System.exit(0);
}else{
clnt.send(readline);
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class clientThread extends Thread {
private CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
private CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();
private Selector sel = null;
private SocketChannel socketChannel = null;
private SelectionKey clntKey = null;
public clientThread(){
try {
sel = Selector.open();
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
clntKey = socketChannel.register(sel, SelectionKey.OP_CONNECT);
socketChannel.register(sel, SelectionKey.OP_CONNECT);
InetSocketAddress ip = new InetSocketAddress(12345);
socketChannel.connect(ip);
} catch (ClosedChannelException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void run(){
try {
while(true){
sel.select();
Iterator<SelectionKey> iterator = sel.selectedKeys().iterator();
while(iterator.hasNext()){
SelectionKey key = iterator.next();
iterator.remove();
if(key.isConnectable()){
SocketChannel channal = (SocketChannel)key.channel();
if(channal.isConnectionPending()){
channal.finishConnect();
}
channal.register(sel, SelectionKey.OP_READ);
System.out.println("连接服务器成功!");
}
else if(key.isReadable()){
SocketChannel channel = (SocketChannel)key.channel();
ByteBuffer bbuf = ByteBuffer.allocate(50);
channel.read(bbuf);
bbuf.flip();
String msg = decoder.decode(bbuf).toString();
System.out.println("收到消息,来自:"+channel.socket().getLocalAddress().getHostAddress() + ":" +
channel.socket().getPort() + ":" + msg);
channel.write(encoder.encode(CharBuffer.wrap
("你好, 我是clnt1!")));
// channel.close();
}
}
}
} catch (ClosedChannelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
sel.close();
socketChannel.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void send(String msg){
try {
SocketChannel channel = (SocketChannel)clntKey.channel();
channel.write(encoder.encode(CharBuffer.wrap(msg)));
} catch (CharacterCodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void close(){
try {
sel.close();
socketChannel.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
出现问题主要有两个:
1.客户端bye之后调用了socketChannel.close();然后server就在控制台一直输出:
收到消息来自:192.168.1.174:4685:
收到消息来自:192.168.1.174:4685:
收到消息来自:192.168.1.174:4685:
收到消息来自:192.168.1.174:4685:
请问server的sel.select();为什么能检测到了事件的发生?明明没有收到client的消息啊?
2.InputStreamReader streamReader = new InputStreamReader(System.in);
BufferedReader reader = new BufferedReader(streamReader);
readline = reader.readLine()
这里从控制台输入汉字“发送” 送字为乱码,如何解决这个问题?
恳请大牛指导
这是一条镜像帖。来源:北邮人论坛 / java / #17017同步于 2010/12/30
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖
请教NIO网络通信
salooloo
2010/12/30镜像同步2 回复
订阅后,新回复会通过你的通知中心匿名送达。
2 条回复
你可以试一下发送前的消息通过Charset.forName("UTF-8").newEncoder.encode(CharBuffer.wrap("发送"));
UTF-8那里换成你自己的编码格式。
【 在 salooloo 的大作中提到: 】
: 一个简单的nio通信例子:
: 服务器端:
: public class serv{
: ...................
题外话,学习nio框架,比如netty