java网络socket编程(七)之java中NIO实现聊天系统的群聊功能
来源:互联网 发布:网络教育 档案 公考 编辑:程序博客网 时间:2024/06/15 08:32
1.服务器端代码
<span style="font-family:Microsoft YaHei;">import java.io.IOException;import java.net.InetSocketAddress;import java.net.ServerSocket;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;import java.util.HashSet;import java.util.Iterator;import java.util.Set;/** * 聊天室服务器 * 网络多客户端聊天室 * 功能1: 客户端通过Java NIO连接到服务端,支持多客户端的连接 * 功能2:客户端初次连接时,服务端提示输入昵称,如果昵称已经有人使用,提示重新输入,如果昵称唯一,则登录成功,之后发送消息都需要按照规定格式带着昵称发送消息 * 功能3:客户端登录后,发送已经设置好的欢迎信息和在线人数给客户端,并且通知其他客户端该客户端上线 * 功能4:服务器收到已登录客户端输入内容,转发至其他登录客户端。 * @author 1 * @date Aug 22, 2016 4:02:01 PM */public class ChatRoomServer {/** 选择器 */private Selector selector;/*****端口号*****/private final static int PORT=9900;/*******在线统计人名或人数********/private HashSet<String> online = new HashSet<String>();/****编码*****/private Charset charset = Charset.forName("UTF-8");/****用户存在提示信息*****/private static String USER_EXIST = "system message: user exist, please change a name"; /****相当于自定义协议格式,与客户端协商好*****/ private static String USER_CONTENT_SPILIT = "#@#"; public static void main(String[] args) {try {new ChatRoomServer().init();} catch (IOException e) {e.printStackTrace();}} /** * 初始化服务器 * @author 1 * @throws IOException */ public void init() throws IOException{ //打开选择器 this.selector = Selector.open(); // 开启服务器端通道,并指定端口号ServerSocketChannel server = ServerSocketChannel.open();ServerSocket serverSocket = server.socket();InetSocketAddress address = new InetSocketAddress(PORT);serverSocket.bind(address);server.configureBlocking(false);//将选择器注册到服务器通道上server.register(selector, SelectionKey.OP_ACCEPT);System.out.println("server is linstening...");//等待客户端的连接while(true){int nums = this.selector.select();if (nums<=0) {continue;}//存在连接Set<SelectionKey> selectionKeys = this.selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {//得到当前的选择键SelectionKey key = iterator.next();iterator.remove();//处理当前的选择键dealWithSelectionKey(server,key);}} }/** * * @param server * @param key * @author 1 * @throws IOException */private void dealWithSelectionKey(ServerSocketChannel server, SelectionKey key) throws IOException {if (key.isAcceptable()) {//接收客户端SocketChannel sChannel = server.accept();//设置非阻塞sChannel.configureBlocking(false);//注册选择器,并设置为读取模式,收到一个连接请求,然后起一个SocketChannel,并注册到selector上,之后这个连接的数据,就由这个socketchannel处理。sChannel.register(selector, SelectionKey.OP_READ);//将此对应的channel设置为准备接收其他客户端的请求key.interestOps(SelectionKey.OP_ACCEPT);System.out.println("Server is listening from client :" + sChannel.socket().getRemoteSocketAddress());sChannel.write(charset.encode("Please input your name:"));}//处理来自客户端的数据读取请求else if (key.isReadable()) {//得到该key对应的channel,其中有数据需要读取SocketChannel sc = (SocketChannel) key.channel();StringBuffer content = new StringBuffer();ByteBuffer buffer = ByteBuffer.allocate(1024);try {//得到客户端传过来的消息while(sc.read(buffer)>0){buffer.flip();content.append(charset.decode(buffer));}//将此对应的channel设置为准备下一次接受数据key.interestOps(SelectionKey.OP_READ);} catch (Exception e) {e.printStackTrace();key.cancel();sc.close();}//如果内容不为空if (content.length()>0) {//拆分规则String[] msgArr = content.toString().split(USER_CONTENT_SPILIT);//注册名字if (msgArr!=null && msgArr.length==1) {//用户已经存在,则直接返回if (online.contains(msgArr[0])) {sc.write(charset.encode(USER_EXIST));}else {String name = msgArr[0];online.add(name);int onlineNum = this.onlineTotal();String msg = "welcome "+name+" to chat room,current online people num is:"+onlineNum;//通知所有的人broadCast(selector, null, msg);}}//聊天内容else if (msgArr!=null && msgArr.length>1) { String name = msgArr[0]; String message = content.substring(name.length()+USER_CONTENT_SPILIT.length()); message = name + " say " + message; if(online.contains(name)) { //不回发给发送此内容的客户端 broadCast(selector, sc, message); }}}} }/** * 通知所有人 * @param selector 选择器 * @param sc 不通知的客户端 * @param msg 消息 * @author 1 * @throws IOException */private void broadCast(Selector selector, SocketChannel except, String msg) throws IOException {for(SelectionKey key : selector.keys()){Channel channel = key.channel();if (channel instanceof SocketChannel && channel != except) {SocketChannel socketChannel = (SocketChannel) channel;socketChannel.write(charset.encode(msg));}}}/** * 得到在线总人数 * @return * @author 1 */private int onlineTotal() {int num=0;for(SelectionKey key : this.selector.keys()){Channel targetchannel = key.channel();if (targetchannel instanceof SocketChannel) {num++;}}return num;} }</span>
2.客户端代码
<span style="font-family:Microsoft YaHei;">package com.hq.io.socket;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.nio.charset.Charset;import java.util.Iterator;import java.util.Scanner;import java.util.Set;/** * * @author 1 * @date Aug 22, 2016 4:02:01 PM */public class ChatRoomClient {private Selector selector = null;static final int port = 9900;private Charset charset = Charset.forName("UTF-8");private SocketChannel sc = null;private String name = "";private static String USER_EXIST = "system message: user exist, please change a name";private static String USER_CONTENT_SPILIT = "#@#";public void init() throws IOException {selector = Selector.open();// 连接远程主机的IP和端口sc = SocketChannel.open(new InetSocketAddress("127.0.0.1", port));sc.configureBlocking(false);sc.register(selector, SelectionKey.OP_READ);// 开辟一个新线程来读取从服务器端的数据new Thread(new ClientThread()).start();// 在主线程中 从键盘读取数据输入到服务器端Scanner scan = new Scanner(System.in);while (scan.hasNextLine()) {String line = scan.nextLine();if ("".equals(line))continue; // 不允许发空消息if ("".equals(name)) {name = line;line = name + USER_CONTENT_SPILIT;} else {line = name + USER_CONTENT_SPILIT + line;}sc.write(charset.encode(line));// sc既能写也能读,这边是写}}private class ClientThread implements Runnable {public void run() {try {while (true) {int readyChannels = selector.select();if (readyChannels == 0)continue;Set selectedKeys = selector.selectedKeys(); // 可以通过这个方法,知道可用通道的集合Iterator keyIterator = selectedKeys.iterator();while (keyIterator.hasNext()) {SelectionKey sk = (SelectionKey) keyIterator.next();keyIterator.remove();dealWithSelectionKey(sk);}}} catch (IOException io) {}}private void dealWithSelectionKey(SelectionKey sk) throws IOException {if (sk.isReadable()) {// 使用 NIO 读取 Channel中的数据,这个和全局变量sc是一样的,因为只注册了一个SocketChannel// sc既能写也能读,这边是读SocketChannel sc = (SocketChannel) sk.channel();ByteBuffer buff = ByteBuffer.allocate(1024);String content = "";while (sc.read(buff) > 0) {buff.flip();content += charset.decode(buff);}// 若系统发送通知名字已经存在,则需要换个昵称if (USER_EXIST.equals(content)) {name = "";}System.out.println(content);sk.interestOps(SelectionKey.OP_READ);}}}public static void main(String[] args) throws IOException {new ChatRoomClient().init();}}</span>
1 0
- java网络socket编程(七)之java中NIO实现聊天系统的群聊功能
- java网络socket编程(八)之java中BIO实现聊天系统的群聊功能
- java socket编程(3)——利用socket实现聊天之群聊
- java socket编程(3)——利用socket实现聊天之群聊
- 基于Socket的java网络编程(实现类似于QQ两人聊天的交互)
- 【java编程】Socket编程之UDP模拟简单聊天功能
- java socket编程(2)——利用socket实现聊天之单聊
- Java整理(七)网络编程Socket
- Java Socket网络编程七
- java 聊天程序 socket网络编程
- java网络编程之NIO(二)
- 一个java网络编程Socket的例子,实现Server与Client聊天
- 使用Java Socket实现简单的聊天功能
- java socket编程(1)——利用socket实现聊天之消息推送
- java socket编程(4)——利用socket实现聊天之上传文件
- java多线程以及java网络编程实现简单的聊天系统
- java nio SocketChannel (聊天功能)+NIO介绍
- java结合NIO实现的聊天程序
- 推荐一款嵌入式Linux的FTP服务端软件(stupid-ftpd)
- eclipse debug的时候提示debug Edit Source Lookup path
- Linux基本命令练习(6)---find
- ImageView ScaleType
- MySQL授权
- java网络socket编程(七)之java中NIO实现聊天系统的群聊功能
- 大数系列——大数乘法
- Scala函数式编程
- 使用深度神经网络对基于脑电的情感识别进行频带和导的探究
- Caffe fine-tuning 微调网络
- Android 使用TabLayout制作下划线能滑动的Tab标签页-design
- linux体系结构与内核结构图解
- codeforces 598D dfs
- 如何建立动态库