Java NIO chat room

Source: Internet
Author: User
Tags sendmsg

I spent two weeks in my spare time reading Java NIO. In general, this book details NIO and focuses on it without too much nonsense, it's just that the translation of the Chinese version is really hard to see, and the English level is too low to be able to help, and I finally insisted on reading it. The focus of the book "Java NIO" is the "selector" explained in Chapter 4. To understand it thoroughly, we should repeat it over and over again; it took me about three days to understand and use NIO's selector mechanism, so I wrote this chat room program.

The following code is used directly. The jdk1.5 and above have been tested to support simultaneous online chat;

Copy the following code to the project to run: Chat Room source code

I. Server Side

Package com. chat. 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. vector;/*** chat room: Server * @ author zing **/public class ChatServer implements Runnable {// Selector private selector Selector; // private SelectionKey serverKey after registering ServerSocketChannel; // identifies whether to run private boolean isRun; // list of user names in the current chat room, private Vector
 
  
Unames; // time formatter SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd HH: mm: ss "); /*** constructor * @ param port: port Number monitored by the server */public ChatServer (int port) {isRun = true; unames = new Vector
  
   
(); Init (port);}/*** initialize the selector and server socket ** @ param port: port Number monitored by the server */private void init (int port) {try {// obtain selector instance Selector = selector. open (); // obtain the server socket instance ServerSocketChannel serverChannel = ServerSocketChannel. open (); // bind the port number serverChannel. socket (). bind (new InetSocketAddress (port); // set to non-blocking serverChannel. configureBlocking (false); // register the ServerSocketChannel to the selector and specify its behavior as "waiting to accept connections" serverKey = serverChannel. register (selector, SelectionKey. OP_ACCEPT); printInfo ("server starting... ");} catch (IOException e) {e. printStackTrace () ;}@ Overridepublic void run () {try {// round robin selector selection key while (isRun) {// select the key of a set of channels for IO operations. If it is equal to 1, the keyint n = selector exists. select (); if (n> 0) {// obtain the set of selected keys from the selector and iterate Iterator
   
    
Iter = selector. selectedKeys (). iterator (); while (iter. hasNext () {SelectionKey key = iter. next (); // if the channel for this key is waiting to accept a new socket connection if (key. isAcceptable () {// remember to remove this key; otherwise, the new connection will be blocked and the server cannot be connected to iter. remove (); // channel for obtaining the key ServerSocketChannel serverChannel = (ServerSocketChannel) key. channel (); // accept the new connection and return the socket channel SocketChannel = serverChannel equivalent to the client. accept (); if (channel = null) {continue;} // you can specify a non-blocking channel. conf IgureBlocking (false); // register the socket channel to the selector and specify its behavior as "read" channel. register (selector, SelectionKey. OP_READ);} // if the channel behavior of this key is "read" if (key. isReadable () {readMsg (key) ;}// if the next key channel behavior is "write" if (key. isWritable () {writeMsg (key) ;}}} catch (IOException e) {e. printStackTrace () ;}}/*** read data from the socket channel corresponding to the key * @ param key selection key * @ throws IOException */private void readMsg (SelectionKey key) throws IOException {// obtain the socket channel Socke corresponding to this key TChannel channel = (SocketChannel) key. channel (); // create a cache with a size of KB. ByteBuffer buffer = ByteBuffer. allocate (1024); StringBuffer sb = new StringBuffer (); // read channel data to the cache area int count = channel. read (buffer); if (count> 0) {// flip the cache (from the write data mode to the read data mode) buffer. flip (); // convert the data in the cache to Stringsb. append (new String (buffer. array (), 0, count);} String str = sb. toString (); // if the message contains "open _", it indicates that the client is about to enter the chat interface. // the data format transmitted by the client is "open_zing", Indicating that the user request to open the chat form with the name zing // the user name list has been updated, the user name data should be written to each connected client if (str. indexOf ("open _")! =-1) {// client connection Server String name = str. substring (5); printInfo (name + "online"); unames. add (name); // obtain the selected key of the selector and iterate the Iterator
    
     
Iter = selector. selectedKeys (). iterator (); while (iter. hasNext () {SelectionKey selKey = iter. next (); // if it is not the key of the server socket channel, set the data to this key // and update the action if (selKey! = ServerKey) {selKey. attach (unames); selKey. interestOps (selKey. interestOps () | SelectionKey. OP_WRITE) ;}} else if (str. indexOf ("exit _")! =-1) {// String uname = str. substring (5); // Delete this user name unames. remove (uname); // append the "close" string to the keykey. attach ("close"); // update the action key of interest to this key. interestOps (SelectionKey. OP_WRITE); // obtain the selected key on the selector and iterate. // append the updated Name List data to the key of each socket channel, and reset the Iterator
     
      
Iter = key. selector (). selectedKeys (). iterator (); while (iter. hasNext () {SelectionKey selKey = iter. next (); if (selKey! = ServerKey & selKey! = Key) {selKey. attach (unames); selKey. interestOps (selKey. interestOps () | SelectionKey. OP_WRITE) ;}} printInfo (uname + "offline");} else {// read client chat message String uname = str. substring (0, str. indexOf ("^"); String msg = str. substring (str. indexOf ("^") + 1); printInfo ("(" + uname + "):" + msg); String dateTime = sdf. format (new Date (); String smsg = uname + "" + dateTime + "\ n" + msg + "\ n"; Iterator
      
        Iter = selector. selectedKeys (). iterator (); while (iter. hasNext () {SelectionKey selKey = iter. next (); if (selKey! = ServerKey) {selKey. attach (smsg); selKey. interestOps (selKey. interestOps () | SelectionKey. OP_WRITE) ;}}}/*** socket channel * @ param key * @ throws IOException */private void writeMsg (SelectionKey key) for writing data to the key) throws IOException {SocketChannel channel = (SocketChannel) key. channel (); Object obj = key. attachment (); // the additional data of the key must be set to null. Otherwise, the key may be faulty. attach (""); // if the added value is "close", cancel the key and close the corresponding channel if (obj. toString (). equals ("close") {key. cancel (); channel. socket (). close (); channel. close (); return;} else {// write data to the channel. write (ByteBuffer. wrap (obj. toString (). getBytes ();} // reset the key interest. interestOps (SelectionKey. OP_READ);} private void printInfo (String str) {System. out. println ("[" + sdf. format (new Date () + "]->" + str);} public static void main (String [] args) {ChatServer server = new ChatServer (19999 ); new Thread (server ). start ();}}
      
     
    
   
  
 

Ii. Client

1. Service class for interaction with the server

package com.chat.client;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SocketChannel;public class ClientService {private static final String HOST = "127.0.0.1";private static final int PORT = 19999;private static SocketChannel sc;private static Object lock = new Object();private static ClientService service;public static ClientService getInstance(){synchronized (lock) {if(service == null){try {service = new ClientService();} catch (IOException e) {e.printStackTrace();}}return service;}}private ClientService() throws IOException {sc = SocketChannel.open();sc.configureBlocking(false);sc.connect(new InetSocketAddress(HOST, PORT));}public void sendMsg(String msg) {try {while (!sc.finishConnect()) {}sc.write(ByteBuffer.wrap(msg.getBytes()));} catch (IOException e) {e.printStackTrace();}}public String receiveMsg() {ByteBuffer buffer = ByteBuffer.allocate(1024);buffer.clear();StringBuffer sb = new StringBuffer();int count = 0;String msg = null;try {while ((count = sc.read(buffer)) > 0) {sb.append(new String(buffer.array(), 0, count));}if (sb.length() > 0) {msg = sb.toString();if ("close".equals(sb.toString())) {msg = null;sc.close();sc.socket().close();}}} catch (IOException e) {e.printStackTrace();}return msg;}}

2. log on to the form and set the name.

Package com. chat. client; import java. awt. toolkit; import java. awt. event. actionEvent; import java. awt. event. actionListener; import javax. swing. JButton; import javax. swing. JFrame; import javax. swing. JLabel; import javax. swing. JTextField;/*** set name form ** @ author zing **/public class SetNameFrame extends JFrame {private static final long serialVersionUID = 1L; private static JTextField txtName; // text box private static JButton btnOK; // OK button private static JLabel label; // label public SetNameFrame () {this. setLayout (null); Toolkit kit = Toolkit. getdefatooltoolkit (); int w = kit. getScreenSize (). width; int h = kit. getScreenSize (). height; this. setBounds (w/2-230/2, h/2-200/2, 230,200); this. setTitle ("Set Name"); this. setdefaclocloseoperation (EXIT_ON_CLOSE); this. setResizable (false); txtName = new JTextField (4); this. add (txtName); txtName. setBounds (10, 10,100, 25); btnOK = new JButton ("OK"); this. add (btnOK); btnOK. setBounds (120, 10, 80, 25); label = new JLabel ("[w:" + w + ", h:" + h + "]"); this. add (label); label. setBounds (10, 40,200,100); label. setText ("Enter the name in the text box above.
Display width: "+ w +"
Display height: "+ h +""); BtnOK. addActionListener (new ActionListener () {@ Overridepublic void actionreceivmed (ActionEvent e) {String uname = txtName. getText (); ClientService service = ClientService. getInstance (); ChatFrame chatFrame = new ChatFrame (service, uname); chatFrame. show (); setVisible (false) ;}}) ;}public static void main (String [] args) {SetNameFrame setNameFrame = new SetNameFrame (); setNameFrame. setVisible (true );}}

3. Chat Room form

Package com. chat. client; import java. awt. event. actionEvent; import java. awt. event. actionListener; import java. awt. event. keyEvent; import java. awt. event. keyListener; import java. awt. event. windowAdapter; import java. awt. event. using wevent; import javax. swing. defaultListModel; import javax. swing. JButton; import javax. swing. JFrame; import javax. swing. JList; import javax. swing. JScrollPane; import javax. swing. JTextAr Ea; import javax. swing. event. listSelectionEvent; import javax. swing. event. listSelectionListener;/*** chat room form * @ author zing **/public class ChatFrame {private JTextArea readContext = new JTextArea (18, 30 ); // display the message text box private JTextArea writeContext = new JTextArea (6, 30); // send the message text box private defalistlistmodel modle = new DefaultListModel (); // user list model private JList list = new JList (modle); // user list private JButt On btnSend = new JButton ("send"); // send message button private JButton btnClose = new JButton ("close "); // close the chat window button private JFrame frame = new JFrame ("ChatFrame"); // form interface private String uname; // user name private ClientService service; // used to interact with the server private boolean isRun = false; // whether to run public ChatFrame (ClientService service, String uname) {this. isRun = true; this. uname = uname; this. service = service;} // initialize the interface control and event private void in It () {frame. setLayout (null); frame. setTitle (uname + "chat window"); frame. setSize (500,500); frame. setLocation (400,200); // you can disable frame. setdefaclocloseoperation (JFrame. EXIT_ON_CLOSE); // The frame size cannot be changed. setResizable (false); // The chat message display area contains the scroll bar JScrollPane readScroll = new JScrollPane (readContext); readScroll. setVerticalScrollBarPolicy (JScrollPane. VERTICAL_SCROLLBAR_AS_NEEDED); frame. add (readScroll); // The message editing area contains a scroll bar JScrollPane. WriteScroll = new JScrollPane (writeContext); writeScroll. setVerticalScrollBarPolicy (JScrollPane. VERTICAL_SCROLLBAR_AS_NEEDED); frame. add (writeScroll); frame. add (list); frame. add (btnSend); frame. add (btnClose); readScroll. setBounds (10, 10,320,300); readContext. setBounds (0, 0,320,300); readContext. setEditable (false); // set to uneditable readContext. setLineWrap (true); // automatically wrap writeScroll. setBounds (10,315,320,100); wr IteContext. setBounds (0, 0,320,100); writeContext. setLineWrap (true); // automatically wrap the list. setBounds (340, 10,140,445); btnSend. setBounds (150,420, 80, 30); btnClose. setBounds (250,420, 80, 30); // close the event frame in the form. addWindowListener (new WindowAdapter () {@ Overridepublic void windowClosing (expose wevent e) {isRun = false; service. sendMsg ("exit _" + uname); System. exit (0) ;}}); // send button event btnSend. addActionListener (new ActionList Ener () {@ Overridepublic void actionreceivmed (ActionEvent e) {String msg = writeContext. getText (). trim (); if (msg. length ()> 0) {service. sendMsg (uname + "^" + writeContext. getText ();} // after sending the message, remove the text in the editing area and obtain the cursor focus writeContext. setText (null); writeContext. requestFocus () ;}}); // close button event btnClose. addActionListener (new ActionListener () {@ Overridepublic void actionreceivmed (ActionEvent e) {isRun = false; service. sendMs G ("exit _" + uname); System. exit (0) ;}}); // select event list from the name list on the right. addListSelectionListener (new ListSelectionListener () {@ Overridepublic void valueChanged (ListSelectionEvent e) {// JOptionPane. showMessageDialog (null, // list. getSelectedValue (). toString () ;}}); // The writeContext event of the keyboard in the message editing area. addKeyListener (new KeyListener () {@ Overridepublic void keyTyped (KeyEvent e) {// TODO Auto-generated method stub} // press the keyboard button to release @ Ove Rridepublic void keyReleased (KeyEvent e) {// press enter to send the message if (e. getKeyCode () = KeyEvent. VK_ENTER) {String msg = writeContext. getText (). trim (); if (msg. length ()> 0) {service. sendMsg (uname + "^" + writeContext. getText ();} writeContext. setText (null); writeContext. requestFocus () ;}@overridepublic void keyPressed (KeyEvent e) {// TODO Auto-generated method stub }});} // This Thread class is used to poll and read the message sent by the server. private class MsgThread Extends Thread {@ Overridepublic void run () {while (isRun) {String msg = service. receiveMsg (); if (msg! = Null) {// if it is name list data, update the list on the right of the chat form if (msg. indexOf ("[")! =-1 & msg. lastIndexOf ("]")! =-1) {msg = msg. substring (1, msg. length ()-1); String [] userNames = msg. split (","); modle. removeAllElements (); for (int I = 0; I <userNames. length; I ++) {modle. addElement (userNames [I]. trim () ;}} else {// set the chat data to the chat message display area String str = readContext. getText () + msg; readContext. setText (str); readContext. selectAll (); // keep the scroll bar at the bottom. init (); service. sendMsg ("open _" + uname); MsgThread msgThread = new MsgThread (); msgThread. start (); this. frame. setVisible (true );}}


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.