- 浏览: 1548 次
- 性别:
- 来自: 南京
最新评论
服务器
package com.ww.server; 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.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Vector; import com.ww.dao.UsersData; import com.ww.entity.Users; public class Server implements Runnable{ //选择器 private Selector selector; //选择key private SelectionKey sscKey; //服务器开关 private boolean isOpen; //用户集合 private List<Users> users; //用户上线列表 private Vector<String> userNames; public Server(int port) { isOpen = true; users = UsersData.dataUsers(); userNames = new Vector<String>(); init(port); } @Override public void run() { try { while(isOpen) { //接收信息的数量 int result = selector.select(); if(result > 0) { for (Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); iterator.hasNext();) { SelectionKey key = (SelectionKey) iterator.next(); iterator.remove(); //判断是否是接收状态 if(key.isAcceptable()) { System.out.println("==========客户端开启=========="); getConn(key); } //判断是否是读取状态 else if(key.isReadable()) { System.out.println("=============读取============="); ReadMsg(key); } //判断是否是写入状态 else if(key.isWritable()) { System.out.println("=============写入============="); WriteMsg(key); } } } } } catch (IOException e) { e.printStackTrace(); } } //初始化服务器 private void init(int port) { try { //开启选择器 selector = Selector.open(); //开启ServerSocket ServerSocketChannel ssc = ServerSocketChannel.open(); //设置非阻塞模式 ssc.configureBlocking(false); //设置端口 ssc.socket().bind(new InetSocketAddress(port)); //注册到选择器里并设置为接收状态 sscKey = ssc.register(selector,SelectionKey.OP_ACCEPT); System.out.println("==========开启服务器=========="); } catch (IOException e) { e.printStackTrace(); } } //获取连接 private void getConn(SelectionKey key) throws IOException { //获取ServerSocket ServerSocketChannel ssc = (ServerSocketChannel)key.channel(); //设置Socket SocketChannel sc = ssc.accept(); //设置非阻塞模式 sc.configureBlocking(false); //注册到选择器里并设置为读取状态 sc.register(selector, SelectionKey.OP_READ); } //读取信息 private void ReadMsg(SelectionKey key) throws IOException { //获取到Socket SocketChannel sc = (SocketChannel)key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024); buffer.clear(); StringBuffer sb = new StringBuffer(); //获取字节长度 int count = sc.read(buffer); if( count > 0 ) { buffer.flip(); sb.append(new String(buffer.array(), 0, count)); } Object obj = (Object)sb.toString(); if(obj.toString().indexOf("-")!= -1) { //获取用户名 String userName = obj.toString().substring(0, obj.toString().indexOf("-")); //获取用户密码 String userPass = obj.toString().substring(obj.toString().indexOf("-") + 1); boolean isTrue = false; //判断用户是否存在 for (int i = 0; i < users.size(); i++) { if(users.get(i).getUserName().equals(userName) && users.get(i).getUserPass().equals(userPass)) { System.out.println("========" + userName + "登录成功========"); isTrue = true; userNames.addElement(userName); KeyAttach(key,"true"); break; } isTrue = false; } //用户不存在 if(!isTrue) { System.out.println("========" + userName + "登录失败========"); KeyAttach(key,"false"); } } else if(obj.toString().equals("open")) { System.out.println("=========开启聊天窗口========="); //给都有的用户返回用户列表 AllKeysAttach(key,userNames); } else if( obj.toString().indexOf("exit_") != -1 ) { String userName = obj.toString().substring(5); userNames.removeElement(userName); System.out.println("========" + userName + "退出窗体========"); KeyAttach(key,"close"); OtherKeysAttach(key,userNames); } else { //获取用户名 String userName = obj.toString().substring(0,obj.toString().indexOf("^")); //获取信息 String mess = obj.toString().substring(obj.toString().indexOf("^")+1); //获取发信时间 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String dateTime = dateFormat.format(new Date()); //设置信息 String mss = userName + " " + dateTime + "\n" + mess + "\n"; //给都有的用户返回聊天信息 AllKeysAttach(key,mss); } } //所有client改成写入状态 private void AllKeysAttach(SelectionKey key,Object obj) { for (Iterator<SelectionKey> iterator = key.selector().keys().iterator(); iterator.hasNext();) { SelectionKey selKey = (SelectionKey) iterator.next(); //判断不是Server key; if( selKey != sscKey ) { selKey.attach(obj); //把其他client改成可写状态 selKey.interestOps( selKey.interestOps() | SelectionKey.OP_WRITE ); } } } //把其他客户改成写入状态 private void OtherKeysAttach(SelectionKey key,Object obj) { for (Iterator<SelectionKey> iterator = key.selector().keys().iterator(); iterator.hasNext();) { SelectionKey selKey = (SelectionKey) iterator.next(); //判断不是本生client key和Server key; if( selKey != sscKey && selKey != key ) { selKey.attach(obj); //把其他client改成可写状态 selKey.interestOps( selKey.interestOps() | SelectionKey.OP_WRITE ); } } } //自身改成写入状态 private void KeyAttach(SelectionKey key,Object obj) { key.attach(obj); key.interestOps(SelectionKey.OP_WRITE); } //发送信息 private void WriteMsg(SelectionKey key) throws IOException { //获取到Socket SocketChannel sc = (SocketChannel)key.channel(); //获取附属值 Object obj = key.attachment(); //把附属值设为空 key.attach(""); //发送信息 sc.write(ByteBuffer.wrap(obj.toString().getBytes())); if(obj.toString().equals("close") || obj.toString().equals("false")) { key.cancel(); sc.socket().close(); sc.close(); System.out.println("==========客户端关闭=========="); return; } //设置为读取状态 key.interestOps(SelectionKey.OP_READ); } public static void main(String[] args) { Server server = new Server(8001); new Thread(server).start(); } }
客户端界面
1.登录界面
package com.ww.frame; import java.awt.Color; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.IOException; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextField; import com.ww.biz.ClientServerBIz; import com.ww.frame.ChatFrame; public class LoginFrame { private JLabel lblTitle = new JLabel("山寨版QQ"), lblUserName = new JLabel("用户名:"), lblPassword = new JLabel("密 码:"); private JTextField txtUserName = new JTextField(15), txtPassword = new JTextField(15); private JButton btnSub = new JButton("提交"), btnRes = new JButton("取消"); private JFrame aFrame = new JFrame("登录山寨QQ"); private ClientServerBIz clientBiz; public LoginFrame() { into(); } private void into() { aFrame.setLayout(null); aFrame.setBounds(300, 300, 200, 180); lblTitle.setBounds(45, 10, 100, 40); lblTitle.setForeground(new Color(120, 120, 120)); lblTitle.setFont(new Font("山寨版QQ", 1, 20)); aFrame.add(lblTitle); lblUserName.setBounds(10, 50, 80, 20); aFrame.add(lblUserName); lblPassword.setBounds(10, 80, 80, 20); aFrame.add(lblPassword); txtUserName.setBounds(65, 50, 120, 20); aFrame.add(txtUserName); txtPassword.setBounds(65, 80, 120, 20); aFrame.add(txtPassword); btnSub.setBounds(10, 110, 80, 25); aFrame.add(btnSub); btnRes.setBounds(100, 110, 80, 25); aFrame.add(btnRes); btnSub.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String userInfo = txtUserName.getText() + "-" + txtPassword.getText(); try { clientBiz = new ClientServerBIz(); clientBiz.sendToServer(userInfo); Object obj = clientBiz.sendToClient(); System.out.println(obj.toString()); if (Boolean.parseBoolean(obj.toString())) { ChatFrame cf = new ChatFrame(clientBiz,txtUserName.getText()); cf.show(); aFrame.setVisible(false); } else { System.out.println("用户不存在或密码错误!"); } } catch (IOException e1) { e1.printStackTrace(); } catch (ClassNotFoundException e1) { e1.printStackTrace(); } } }); btnRes.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.exit(0); } }); aFrame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } }); } public void show() { aFrame.setVisible(true); } public static void main(String[] args) { LoginFrame login = new LoginFrame(); login.show(); } }
2.聊天界面
package com.ww.frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.IOException; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JTextArea; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import com.ww.biz.ClientServerBIz; public class ChatFrame { //文本框 private JTextArea readContext = new JTextArea(18,30),//显示信息 writeContext = new JTextArea(6,30);//发送信息 //列表框 private DefaultListModel modle = new DefaultListModel();//列表模型 private JList list = new JList(modle);//列表 //按钮 private JButton btnSub = new JButton("提交"),//提交按钮 btnRes = new JButton("取消");//取消按钮 //窗体界面 private JFrame aFrame = new JFrame("ChatFrame"); //用户名 private String userName; //Client业务类 private ClientServerBIz userBiz; //设置线程是否运行 private boolean isConntext = false; //构造方法 public ChatFrame(ClientServerBIz clientBiz,String userName) { //获取用户名 this.userName = userName; userBiz = clientBiz; //开启线程 isConntext = true; new Thread(new ctUsers()).start(); } //初始化界面 private void init() throws IOException, ClassNotFoundException { aFrame.setLayout(null); aFrame.setTitle(userName+" 聊天窗口"); aFrame.setSize(500, 500); aFrame.setLocation(400, 200); readContext.setBounds(10, 10, 320, 285); readContext.setEditable(false); writeContext.setBounds(10, 305, 320, 100); list.setBounds(340, 10, 140, 445); aFrame.add(readContext); aFrame.add(writeContext); aFrame.add(list); btnSub.setBounds(150, 415, 80, 30); btnRes.setBounds(250, 415, 80, 30); //frame的关闭按钮事件 aFrame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { isConntext = false; //发送关闭信息 userBiz.sendToServer("exit_" + userName); System.exit(0); } }); //提交按钮事件 btnSub.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { //发送信息 userBiz.sendToServer(userName + "^" + writeContext.getText()); writeContext.setText(null); } }); //关闭按钮事件 btnRes.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { isConntext = false; //发送关闭信息 userBiz.sendToServer("exit_" + userName); System.exit(0); } }); list.addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { JOptionPane.showMessageDialog(null,list.getSelectedValue().toString()); } }); aFrame.add(btnSub); aFrame.add(btnRes); aFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } //界面显示 public void show() throws IOException, ClassNotFoundException { init(); aFrame.setVisible(true); userBiz.sendToServer("open"); } class ctUsers extends Thread { public void run() { while(isConntext) { //获取服务器传过的值 Object obj = userBiz.sendToClient(); //判断值是否有空 if(obj != null) { if(obj.toString().indexOf("[") != -1 && obj.toString().lastIndexOf("]") != -1) { obj = obj.toString().substring(1, obj.toString().length()-1); String [] userNames = obj.toString().split(","); modle.removeAllElements(); for (int i = 0; i < userNames.length; i++) { modle.addElement(userNames[i].trim()); } } else { String str = readContext.getText() + obj.toString(); readContext.setText(str); } } } } } }
客户端业务类
package com.ww.biz; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; public class ClientServerBIz { private SocketChannel sc; public ClientServerBIz() throws IOException { sc = SocketChannel.open(); sc.configureBlocking(false); sc.connect(new InetSocketAddress("localhost",8001)); } //发送信息到服务器 public void sendToServer(Object obj) { try { while(!sc.finishConnect()) {} sc.write(ByteBuffer.wrap(obj.toString().getBytes())); } catch (IOException e) { e.printStackTrace(); } } //获取服务器信息传递信息到客户端 public Object sendToClient() { ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024); buffer.clear(); StringBuffer sb = new StringBuffer(); int count = 0; Object obj = null; try { //获取字节长度 Thread.sleep(100); while ((count = sc.read(buffer)) > 0) { sb.append(new String(buffer.array(), 0, count)); } if( sb.length() > 0 ) { obj = sb.toString(); if("close".equals(sb.toString())) { obj = null; sc.close(); sc.socket().close(); } } } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } return obj; } }
数据源
package com.ww.dao; import java.util.ArrayList; import java.util.List; import com.ww.entity.Users; public class UsersData { public static List<Users> dataUsers() { List<Users> users = new ArrayList<Users>(); Users user1 = new Users("tiantian","123456"); Users user2 = new Users("dongdong","123456"); Users user3 = new Users("xiaoxiao","123456"); Users user4 = new Users("mingming","123456"); users.add(user1); users.add(user2); users.add(user3); users.add(user4); return users; } }
实体
package com.ww.entity; import java.io.Serializable; public class Users implements Serializable{ private String userName; private String userPass; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPass() { return userPass; } public void setUserPass(String userPass) { this.userPass = userPass; } public Users(String userName,String userPass) { this.userName = userName; this.userPass = userPass; } }
各位大侠小弟有地方写的不好的地方请指点一二!
发表评论
文章已被作者锁定,不允许评论。
相关推荐
此项目基于java nio实现聊天室功能
用java nio写的一个完整的、可运行的聊天室程序;复制代码到项目后可直接运行。
基于NIO的聊天室
基于nio 简易聊天室的服务端 客户端,有界面
UDP NIO聊天系统,基于UDP通道,NIO,包括服务器端和客户端
java NIO 高性能 socket通讯,服务端采用单线程,降低了cpu的压力,普通io socket通讯,server需要每个连接运行个线程,容易出现问题,效率也低
NIO框架实现的简单聊天室,分为客户端和服务器端,为大家了解NIO作为一个参考
基于NIO编写的聊天室,命令行运行,分server,client,config三个包,分别存放服务器端,客户端,以及一些端口信息的配置类。
本代码是基于JAVA技术NIO流的选择器Selector的多人聊天室,实现了多个客户端之间的聊天,拥有java窗体、画板等。
服务端程序基于javaNIO,客户端程序基于旧IO,读完<<javaNIO>>后,导入eclipse即可运行,支持多人在线聊天,上下线通知.PS:非GUI程序,毕竟javaSwing用的少,不懂的地方大家可以一起讨论,评论必回!
1.学习时的一个聊天室程序,将服务端改为NIO机制 2.支持多人同时在线局域网聊天 3.知识面:JSwing,NIO,消息包加密,解密,单列模式的线程安全机制等.
基于NIO的多线程聊天系统,代码很少,很经典,51CTO网站上的代码。有登陆和聊天界面。代码结构层次清晰,系统只有6个类。
MyDialog md=new MyDialog(LoginFrame.this,"提示窗口","错误!","用户名或密码错误.\n登陆失败"); md.showDialog(); } } else { if(nameLength==0) { MyDialog md=...
主要介绍了Java NIO实战之聊天室功能,结合实例形式详细分析了java NIO聊天室具体的服务端、客户端相关实现方法与操作注意事项,需要的朋友可以参考下
使用NIO socket不需要多线程来处理多个连接的请求,效率非常高 可以作为NIO socket入门的例子,Reactor模式,重点理解key.attach, jar文件里包含了源代码 1,运行server.bat启动服务器,可以打开编辑,修改端口号 ...
相比于上次的基于BIO的多人聊天室的线程数量大幅度减少。 一个线程用于监听客户端的到达,两个线程池分别负责客户端 消息的 读 和写。 另外两个线程 负责 readSelector 和writeSelector 的监听。 但是仅仅是对 ...
简单修改后的版本,与上一次的代码相比,这次加上了发送信息的校验,用户没有昵称和信息内容是不可以发送的。 对上一次代码中同时启动两个客户端CPU占100%的BUG做了修改。
用Netty实现NIO Socket聊天系统示例 ,完整代码,已开源,希望大家多提意见。
一个简单的javaNIO非阻塞的聊天小demo,支持单聊和群聊