简单的的多人聊天端
package cgh20130727分部实现多人通信;import java.io.IOException;import javax.swing.JTextArea;/** * 定义一个TestServer的类创建一个服务器 * @author Allen * */public class TestServer extends Thread {private int port;private JTextArea jta;//构造方法进行参数的传递public TestServer(int port,JTextArea jta){this.port = port;this.jta = jta;}//空参数构造方法 public TestServer() {} //重写run方法 public void run(){ server(port); }//定义一个创建一个服务器的方法public void server(int port){try {//创建服务器java.net.ServerSocket server = new java.net.ServerSocket(port);System.out.println("你的服务器创建成功了!!!\r\n"+"端口号: "+port);while(true){//阻塞等待客户端的连接java.net.Socket soclicent = server.accept(); //创建一个多线程对象ServerThread sth = new ServerThread(soclicent,jta);sth.start();//线程开始运行chatList.add(sth);}} catch (IOException e) { e.printStackTrace();}}}?创建一个服务器代码就那么三行,比较固定看看书也就搞定了.但在程序运行的时候遇到了一个bug,就是在已有的界面上(服务器界面)显示的时候点击"端口"按钮创建服务器对象的时候一直处于运行状态,最后知道了原来是没有添加线程的原因.
?
package cgh20130727分部实现多人通信;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import javax.swing.JTextArea;import cgh20130728多人聊天客户端.customListe;/** * 定义一个客户端对象继承自多线程 * @author Allen * */public class ServerThread extends Thread {private java.net.Socket soclicent;//定义一个客户端的属性private java.io.InputStream ins;private java.io.OutputStream ous;private String ip;private int port;private JTextArea jta; //构造方法进行参数的传递public ServerThread(java.net.Socket soclicent,JTextArea jta){this.soclicent = soclicent;this.jta = jta;}public ServerThread(String ip,int port,JTextArea jta){this.ip = ip;this.port = port;this.jta = jta;}//重写线程run的方法public void run(){work(this.soclicent);}//定义从客户端连接到服务器的方法public void work(java.net.Socket soclicent){try {//客户端接收输入输出流ins = soclicent.getInputStream();ous = soclicent.getOutputStream();//验证是否连接成功String str = "hello,welcome to Lanjie!!!"+"\r\n";byte [] bytes = str.getBytes();ous.write(bytes);ous.flush(); //将字符串读到服务器 String strRead = readString(ins); //判断当读到exit时停止 while(!strRead.equals("exit")){System.out.println("服务器接收到的内容是++++\r\n"+strRead);String sing = "客户端保存的内容是----\r\n"+strRead; byte [] by = sing.getBytes();// ous.write(by);// ous.flush();//强制刷新chatList.sendMsg(by);//客户端接收到的消息jta.setText(strRead);//将客户端接收到的消息显示在文本框中 strRead = readString(ins);//下一次得到的字符串 } }catch (IOException e) {e.printStackTrace();}} //定义一个读入字符串的方法public String readString(java.io.InputStream ins){//创建一个字符串缓冲器对象StringBuffer strb = new StringBuffer();int reads = 0;//判断当读到回车是停止字符的存入while(reads != 35){try {reads = ins.read();//将字符读入到服务器strb.append((char)reads);//将读到的字符放入字符串缓冲区} catch (IOException e) {e.printStackTrace();}}String sting = strb.toString().trim();//将缓冲区的字符整合成字符串return sting;}//定义一个服务器发送消息的方法public void writeMsg(byte [] by){try {System.out.println("writeMsg执行了");ous.write(by);ous.flush();} catch (IOException e) {e.printStackTrace();}}}?写该类的时候遇到的一个是:当在程序运行的时候,不管是服务器的界面文本框还是客户端的文本框一直没有显示,纠结了半天最后终于找到原来是没有写该条指令jta.setText(strRead);
?
?
?
package cgh20130727分部实现多人通信;import java.util.ArrayList;import java.util.List;/** * 定义一个chatList的队列类用来存储客户端对象 * @author Allen * */public class chatList {//定义一个私有的构造方法 private chatList(){ } //调用系统提供的数组队列public static List<ServerThread> list = new ArrayList<ServerThread>();//定义一个数组队列的添加方法public static void add(ServerThread sth){list.add(sth);}//定义一个发送消息的方法public static void sendMsg(byte [] by){System.out.println("sendMsg执行了");//循环遍历数组队列for(int i=0;i<list.size();i++){ServerThread st = list.get(i);st.writeMsg(by);}}}?该类主要是实现将ServerThread保存数组队列中,然后调用sendMsg(by);方法实现客户端与客户端之间,客户端与服务器之间互相发送消息.
?
?
?
package cgh20130727分部实现多人通信;import java.awt.Dimension;import java.awt.FlowLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JOptionPane;import javax.swing.JTextArea;import javax.swing.JTextField;/** * 创建一个服务器界面类 * @author Allen * */public class ServerUI extends JFrame{private JTextArea jta;private TestServer tse;private int nport;/** * 定义一个程序的入口主函数 * @param args */public static void main(String[] args) {//创建一个对象并调用窗体初始化的方法ServerUI sui = new ServerUI();sui.INtUI();}//定义一个窗体初始化的方法public void INtUI() {this.setTitle("服务器");this.setSize(400,300);this.setLocationRelativeTo(null);this.setResizable(false);//设置窗体的流式布局this.setLayout(new FlowLayout());//创建按钮对象JButton jbu = new JButton("端口");JButton jbu1 = new JButton("发送");//创建文本框对象final JTextField jte = new JTextField(25);final JTextField jte1 = new JTextField(25);//创建一个纯文本多行区域jta = new JTextArea(); jta.setPreferredSize(new Dimension(350,180)); //添加到窗体 this.add(jbu); this.add(jte); this.add(jbu1); this.add(jte1); this.add(jta); //创建监听器 ActionListener action = new ActionListener(){//调用事件监听器的方法 public void actionPerformed(ActionEvent e) {if(e.getActionCommand().equals("端口")){nport = Integer.parseInt(jte.getText());tse = new TestServer(nport,jta);//创建客户端对象tse.start();//调用连接服务器的方法System.out.println("------>"+nport);}if(e.getActionCommand().equals("发送")){//从文本框得到消息String info = jte1.getText();//服务器将消息发送给每个客户端chatList.sendMsg(info.getBytes());//服务器的文本区域得到文本jta.append("fuwuqi : \r\n"+info);//发送完毕后清空文本框jte1.setText("");System.out.println("服务器发送消息给客户端成功"+info);}} }; jbu.addActionListener(action); jbu1.addActionListener(action);//按钮添加监听器//设置窗体可见性this.setVisible(true);}}该类主要是写一个服务器的界面并实现创建服务器,群发消息的方法
?
package cgh20130727分部实现多人通信1;import java.awt.Dimension;import java.awt.FlowLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JTextArea;import javax.swing.JTextField;import cgh20130727分部实现多人通信.ServerThread;import cgh20130727分部实现多人通信.chatList;/** * 创建一个客户端的界面继承自JFrame * @author Allen * */public class KehuduanUI extends JFrame {private JTextArea jta;private KehuWay khw;/** * 程序的入口主函数 * @param args */public static void main(String[] args) { //实例化一个对象并调用窗体初始化的方法KehuduanUI khd= new KehuduanUI();khd.INtUI();}//初始化一个界面的方法public void INtUI() {this.setTitle("客户端");this.setSize(400,300);this.setLocationRelativeTo(null);this.setResizable(false);//设置窗体的流式布局this.setLayout(new FlowLayout());//创建按钮对象JButton jbu = new JButton("连接");JButton jbu1 = new JButton("群聊");//创建文本框对象 JTextField jte = new JTextField(25);final JTextField jte1 = new JTextField(25);//创建一个纯文本多行区域jta = new JTextArea(); jta.setPreferredSize(new Dimension(350,180)); //添加到窗体 this.add(jbu); this.add(jte); this.add(jbu1); this.add(jte1); this.add(jta); //创建监听器 ActionListener action = new ActionListener(){//调用监听器的方法 public void actionPerformed(ActionEvent e) {if(e.getActionCommand().equals("连接")){khw = new KehuWay("localhost",9007,jta);//创建一个客户端对象//判断客户端是否创建成功if(khw.connectServer()){khw.start();}}if(e.getActionCommand().equals("群聊")){ String stri = jte1.getText();jta.append("kehuduan : \r\n"+stri+"\r\n");khw.sendInfo(stri);jte1.setText("");//发完后清空文本框}} }; //添加监听器 jbu.addActionListener(action); jbu1.addActionListener(action); //显示窗体的可见性 this.setVisible(true);}}?有了客户端界面就需要有一个服务器的界面.
?
package cgh20130727分部实现多人通信1;import java.io.BufferedReader;import java.io.IOException;import javax.swing.JTextArea;import cgh20130727分部实现多人通信.chatList;/** * 定义客户端方法的类继承自多线程 * @author Allen * */public class KehuWay extends Thread {private String ip;private int port;private java.io.OutputStream ous;private java.io.InputStream ins;private BufferedReader bufr;private JTextArea jta;private String sting;private String string = null;//构造方法进行参数的传递public KehuWay(String ip,int port,JTextArea jta){this.ip = ip;this.port = port;this.jta = jta;}//判断客户端是否与服务器连接成功public boolean connectServer(){try {//创建连接服务器的对象java.net.Socket client = new java.net.Socket(ip,port);System.out.println("客户端与服务器连接成功了!!!");//获取输入输出流ins = client.getInputStream();ous = client.getOutputStream();System.out.println("----++++");return true;} catch (IOException e) {e.printStackTrace();}return false;}//客户端发送消息public void sendInfo(String info){try {//info+="\r\n";ous.write(info.getBytes());ous.flush();//强制刷新} catch (IOException e) {e.printStackTrace();} }//客户端接收消息的方法public void readInfo(){ System.out.println("readInfo执行了!"); while(true){ //创建一个字符串缓冲器对象 StringBuffer strb = new StringBuffer(); int reads = 0; //判断当读到回车是#字符的存入 while(reads != 35){ try { reads = ins.read();//将字符读入到服务器 strb.append((char)reads);//将读到的字符放入字符串缓冲区 } catch (IOException e) { e.printStackTrace(); } }// System.out.println("while(reads != 13)循环退出了"); sting = strb.toString().trim();//将缓冲区的字符整合成字符串 System.out.println("客户端接收到的消息是: "+sting); jta.setText(sting); if(sting == "exit"){ break; } } System.out.println("readInfo结束!"); }//重写run方法public void run(){System.out.println("客户端的run方法执行了");readInfo();System.out.println("客户端的run方法结束了");}}?写该类遇到的一个问题就是,当执行readInfo();方法的时候,少些了while(true){}的一个死循环.当没有该循环的时候读入的方法只是执行一次当读到#的时候程序结束了readInfo(),同时也就结束了run();方法跳出了线程,这之后读不到了消息
?
?