【Java】NIO 客户端-服务器 聊天 例子
来源:互联网 发布:室内网络布线 编辑:程序博客网 时间:2024/05/18 00:39
想写一个简单的聊天C/S,client可以单聊和群发,代码里面有每一次发送的格式。
发现没写过NIO还真不习惯这种模式,总体感觉是不管哪一端,最终都有一个select的循环,然后循环里面会对每一个就绪的key处理,key的处理又是一种宏观的写法,read或者write的处理会包括每一个通道的处理,所以这些函数可能会有很多的case,写起来还是挺费劲的。但是基本还是遵循了服务器的请求-相应模式。就是最开始是一个accept事件,然后有了socket以后,就先注册一个read事件,这个read是用来获取客户端的请求的,然后一旦有了read事件,就需要在处理函数里解析客户端发来的请求,然后再注册一个wirte事件,这样在下一个周期,就会触发write事件,再根据上一次解析的内容把信息写入,最后再重新注册read事件。这是一次请求-响应的基本逻辑,只不过在read函数和write函数里写起来费劲,因为要照顾到所有的channel,感觉分开会更好把。
与传统的io不同点在于,传统io每一次读到客户端请求,就可以直接写内容回去,但是nio无法做到,因为同一个通道的读和写肯定是在两个周期或者两次while循环,这就涉及到了一个如何在第二次的write周期找到上一个read周期解析以后得到的要发送的内容,这个显然需要一个全局的list或者变量来存储,涉及到一些共享变量的东西。个人感觉用多线程做这个比较好把。慢慢研究。
服务端:
package server;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.ClosedChannelException;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Date;import java.util.HashMap;import java.util.Iterator;import java.util.LinkedList;import java.util.List;import java.util.Map;import java.util.Map.Entry;public class Server {private Selector selector;private static final int PORT = 20001;Map<String, SelectionKey> map1;Map<SelectionKey, String> map2;List<Msg> msgs;public void connect(SelectionKey key){ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();System.out.println("log: client connects...");try {SocketChannel socketChannel = serverChannel.accept();socketChannel.configureBlocking(false);socketChannel.register(selector, SelectionKey.OP_READ);} catch (ClosedChannelException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}public void read(SelectionKey key){SocketChannel socketChannel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);StringBuffer sb = new StringBuffer();int c = 0;try {while((c = socketChannel.read(buffer)) > 0){buffer.flip();int size = buffer.remaining();byte[] bytes = new byte[size];buffer.get(bytes, 0, size);sb.append(new String(bytes));}if(c == -1){System.out.println("log: client closes");socketChannel.close();return;}else{System.out.println("log: msg-> " + sb);handleMsg(sb.toString(), key);}} catch (IOException e) {e.printStackTrace();}}private void write(SelectionKey key){SocketChannel sc = (SocketChannel) key.channel();Iterator<Msg> itr = msgs.iterator();while(itr.hasNext()){Msg msg = itr.next();if(msg.getWho().equals("all") || msg.getWho().equals(map2.get(key))){ByteBuffer buffer = ByteBuffer.allocate(1024);String m = "[" + msg.getTime() + "]: " + msg.getMsg();buffer.put(m.getBytes());buffer.flip();try {sc.write(buffer);} catch (IOException e) {e.printStackTrace();}}}try {sc.register(selector, SelectionKey.OP_READ);} catch (ClosedChannelException e) {e.printStackTrace();}}//格式: cmd(who):msg//login:ly//send(all):hello//send(ly):helloprivate void handleMsg(String msg, SelectionKey key){String[] parse = msg.split(":");String cmd = parse[0];if(cmd.equals("login")){map1.put(parse[1], key);map2.put(key, parse[1]);}else if(cmd.startsWith("send")){Msg message = new Msg();DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String date = df.format(new Date());message.setTime(date);int start = cmd.indexOf('(');int end = cmd.indexOf(')');String who = cmd.substring(start + 1, end);message.setWho(who);message.setMsg(parse[1]);msgs.add(message);if(who.equals("all")){for(Entry<String, SelectionKey> entry : map1.entrySet()){SelectionKey sKey = entry.getValue();SocketChannel sc = (SocketChannel) sKey.channel();try {sc.register(selector, sKey.interestOps() | SelectionKey.OP_WRITE);} catch (ClosedChannelException e) {e.printStackTrace();}}}else{SelectionKey sKey = map1.get(who);SocketChannel sc = (SocketChannel) sKey.channel();try {sc.register(selector, sKey.interestOps() | SelectionKey.OP_WRITE);} catch (ClosedChannelException e) {e.printStackTrace();}}}else{//其余的不做处理,仍然监听read}}public void start(){map1 = new HashMap<>();map2 = new HashMap<>();msgs = new LinkedList<>();try {this.selector = Selector.open();ServerSocketChannel serverChannel = ServerSocketChannel.open();serverChannel.configureBlocking(false);serverChannel.bind(new InetSocketAddress(PORT));serverChannel.register(selector, SelectionKey.OP_ACCEPT, "server");System.out.println("log: sever starts...");boolean write = false;while(selector.select() > 0){Iterator<SelectionKey> itr = selector.selectedKeys().iterator();while(itr.hasNext()){SelectionKey key = itr.next();if(key.isAcceptable()){connect(key);}else if(key.isReadable()){read(key);}else if(key.isWritable()){write(key);write = true;}itr.remove();}if(write)msgs.clear();}} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) {new Server().start();}}
Msg类:
package server;public class Msg {private String msg;private String who;private String time;public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public String getWho() {return who;}public void setWho(String who) {this.who = who;}public String getTime() {return time;}public void setTime(String time) {this.time = time;}}客户端:
package client;import java.io.IOException;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.util.Iterator;import java.util.Scanner;public class Client {private Selector selector;private Scanner sc = new Scanner(System.in);public static void main(String args[]){new Client().start();}private void start(){try {selector = Selector.open();SocketChannel socketChannel = SocketChannel.open();socketChannel.configureBlocking(false);socketChannel.register(selector, SelectionKey.OP_CONNECT);socketChannel.connect(new InetSocketAddress("localhost", 20001));while(true){selector.select();Iterator<SelectionKey> itr = selector.selectedKeys().iterator();while(itr.hasNext()){SelectionKey key = itr.next();SocketChannel channel = (SocketChannel) key.channel();if(key.isConnectable()){System.out.println("con");socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);socketChannel.finishConnect(); }else if(key.isReadable()){System.out.println("read");ByteBuffer buffer = ByteBuffer.allocate(1024);channel.read(buffer);String m = new String(buffer.array());System.out.println(m);}else{System.out.println("write");String m = sc.next();ByteBuffer buffer = ByteBuffer.allocate(1024);buffer.put(m.getBytes());buffer.flip();channel.write(buffer);}//itr.remove();}}} catch (IOException e) {e.printStackTrace();}}}这次虽然写出来了,但是感觉还有好多地方需要理解和改进。
阅读全文
0 0
- 【Java】NIO 客户端-服务器 聊天 例子
- JAVA基于NIO客户端对客户端简单聊天DEMO(服务器转发消息)
- Java聊天软件服务器+客户端源码---…
- Java 利用 Socket 实现服务器客户端聊天
- java多线程服务器,实现客户端间聊天
- JAVA NIO 服务器与客户端实现示例
- 基于Java NIO的即时聊天服务器模型
- 基于Java NIO的即时聊天服务器模型
- 基于Java NIO的即时聊天服务器模型
- 聊天服务器-客户端
- 【Java】Java多线程实现的聊天客户端和服务器
- java socket服务器客户端多线程小例子
- java socket/serversocket/thread 服务器客户端任意聊天
- Java局域网聊天系统(服务器客户端一对一)
- Java 实现TCP网络聊天[服务器-客户端]UI界面
- Java NIO编写Socket服务器的一个例子
- Java NIO编写Socket服务器的一个例子
- JAVA NIO 服务器与客户端实现示例(代码1)
- 下拉刷新上拉加载RecycleView效果出众
- 明日(2017.10.30)待整理的文件
- android studio自动整理代码快捷键
- Android文件打开方式,获取相对应type,万能
- Python 习题里程碑
- 【Java】NIO 客户端-服务器 聊天 例子
- Python-------字符串操作
- 杭电oj
- 百度:缩水90亿后,AI商业化能否扭转逆势?
- 未来计算是什么样的?张晓东、丛京生等六大教授这样说 | 未来论坛 2017
- VIPKID项碧波:利用大数据实现个性化教育规模化
- mysql组复制单主模式
- Windows下bat同jar交互
- 十年后,程序员还会有今天的收入吗?