class="java" name="code">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();方法跳出了线程,这之后读不到了消息
?
?