博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaSE聊天室
阅读量:5068 次
发布时间:2019-06-12

本文共 47055 字,大约阅读时间需要 156 分钟。

今天学习了一下简单聊天程序(类似QQ那种)的编写过程,从最初的0.1版本到最后的1.3版本,功能不断地增强,下面对一天的学习内容进行梳理。

版本0.1

我们的需求是显示一个窗体,其他什么也不用做,其他功能逐步添加,我们这里用的就是AWT中的Frame;

具体代码实现:

1 import java.awt.*; 2  3 public class ChatClient extends Frame{ 4  5     /** 6      * @param args 7      */ 8     public static void main(String[] args) { 9         new ChatClient().launchFrame();10     }11 12     /**13      * Version 0.114      */15     public void launchFrame(){16         //设置Frame位置17         setLocation(400, 300);18         //设置Frame大小19         this.setSize(300, 300);20         //窗口可见21         setVisible(true);22     }23 }

版本0.2

我们的需求是在我们的Frame中添加两个部件TextField(用于输入)和TextArea(用于显示获取的内容),此时我们可以在输入框输入内容,但是显示框无法显示我们输入的内容.

1 import java.awt.*; 2  3 public class ChatClient extends Frame { 4  5     TextField tfTxt = new TextField(); 6     TextArea taContent = new TextArea(); 7  8     public static void main(String[] args) { 9         new ChatClient().launchFrame();10     }11 12     /**13      * Version 0.214      */15     public void launchFrame() {16         // 设置Frame位置17         setLocation(400, 300);18         // 设置Frame大小19         this.setSize(300, 300);20         // 将输入框TextField加到Frame中,并放置到Frame布局的上面21         add(tfTxt, BorderLayout.SOUTH);22         // 将显示框TextArea加到Frame中,并放置到Frame布局的下面23         add(taContent, BorderLayout.NORTH);24         // 调整布局,处理多余空白框25         pack();26         // 窗口可见27         setVisible(true);28     }29 }

版本0.3

因为我们的版本0.2中,显示的窗体无法关闭(除非把程序停掉,我们这里不考虑这种做法),我们添加窗口监听,使我们可以通过点击窗体的(X)符号进行关闭;

1 import java.awt.*; 2 import java.awt.event.*; 3  4 public class ChatClient extends Frame { 5  6     TextField tfTxt = new TextField(); 7     TextArea taContent = new TextArea(); 8  9     public static void main(String[] args) {10         new ChatClient().launchFrame();11     }12 13     /**14      * Version 0.3:添加窗口关闭的功能15      */16     public void launchFrame() {17         // 设置Frame位置18         setLocation(400, 300);19         // 设置Frame大小20         this.setSize(300, 300);21         // 将输入框TextField加到Frame中,并放置到Frame布局的上面22         add(tfTxt, BorderLayout.SOUTH);23         // 将显示框TextArea加到Frame中,并放置到Frame布局的下面24         add(taContent, BorderLayout.NORTH);25         // 调整布局,处理多余空白框26         pack();27         //添加窗口监听28         this.addWindowListener(new WindowAdapter() {29 30             @Override31             public void windowClosing(WindowEvent e) {32                 System.exit(0);33             }        34         });35         36         // 窗口可见37         setVisible(true);38     }39 }

版本0.4

我们实现的功能是将输入框输入的内容显示到显示框TextArea中,

1 import java.awt.*; 2 import java.awt.event.*; 3  4 public class ChatClient extends Frame { 5  6     TextField tfTxt = new TextField(); 7     TextArea taContent = new TextArea(); 8  9     public static void main(String[] args) {10         new ChatClient().launchFrame();11     }12 13     /**14      * Version 0.415      */16     public void launchFrame() {17         // 设置Frame位置18         setLocation(400, 300);19         // 设置Frame大小20         this.setSize(300, 300);21         // 将输入框TextField加到Frame中,并放置到Frame布局的上面22         add(tfTxt, BorderLayout.SOUTH);23         // 将显示框TextArea加到Frame中,并放置到Frame布局的下面24         add(taContent, BorderLayout.NORTH);25         // 调整布局,处理多余空白框26         pack();27         // 添加窗口监听28         this.addWindowListener(new WindowAdapter() {29 30             @Override31             public void windowClosing(WindowEvent e) {32                 System.exit(0);33             }34         });35 36         // 将监听器类TFListener添加到输入框TextField中37         tfTxt.addActionListener(new TFListener());38         // 窗口可见39         setVisible(true);40     }41 42     // 建立私有的监听器类,TextField监听:将TextField内容放置到TextArea43     private class TFListener implements ActionListener {44 45         @Override46         public void actionPerformed(ActionEvent e) {47             //获得输入框的内容,并去除两端的空格48             String s = tfTxt.getText().trim();49             //将获取的输入内容放置到TextArea中50             taContent.setText(s);51             //每次输入结束,将输入框置空52             tfTxt.setText("");53         }54     }55 }

版本0.5

相比版本0.4,我们添加了Server端,使得Server作为中转站,把我们输入的内容显示在其他连接到Server端的客户端的的显示框中;

ChatClient

1 import java.awt.*; 2 import java.awt.event.*; 3  4 public class ChatClient extends Frame { 5  6     TextField tfTxt = new TextField(); 7     TextArea taContent = new TextArea(); 8  9     public static void main(String[] args) {10         new ChatClient().launchFrame();11     }12 13     /**14      * Version 0.5:处理输入框15      */16     public void launchFrame() {17         // 设置Frame位置18         setLocation(400, 300);19         // 设置Frame大小20         this.setSize(300, 300);21         // 将输入框TextField加到Frame中,并放置到Frame布局的上面22         add(tfTxt, BorderLayout.SOUTH);23         // 将显示框TextArea加到Frame中,并放置到Frame布局的下面24         add(taContent, BorderLayout.NORTH);25         // 调整布局,处理多余空白框26         pack();27         // 添加窗口监听28         this.addWindowListener(new WindowAdapter() {29 30             @Override31             public void windowClosing(WindowEvent e) {32                 System.exit(0);33             }34         });35 36         // 将监听器类TFListener添加到输入框TextField中37         tfTxt.addActionListener(new TFListener());38         // 窗口可见39         setVisible(true);40     }41 42     // 建立私有的监听器类,TextField监听:将TextField内容放置到TextArea43     private class TFListener implements ActionListener {44 45         @Override46         public void actionPerformed(ActionEvent e) {47             // 获得输入框的内容,并去除两端的空格48             String s = tfTxt.getText().trim();49             // 将获取的输入内容放置到TextArea中50             taContent.setText(s);51             // 每次输入结束,将输入框置空52             tfTxt.setText("");53         }54     }55 }
View Code

Server

1 import java.io.IOException; 2 import java.net.*; 3  4 //server端 5 public class ChatServer { 6  7     /** 8      * @param args 9      */10     public static void main(String[] args) {11         try {12             ServerSocket ss = new ServerSocket(8888);13             while(true){14                 Socket s=ss.accept();15 System.out.println("a clint connected");16             }17         } catch (IOException e) {18             e.printStackTrace();19         }20     }21 }
View Code

此时,我们可以运行多个客户端,但是每个客户端输入的内容在其他客户端都无法显示,他们都是孤立的,还没有与Server端建立连接;

版本0.6

ChatClient

1 import java.awt.*; 2 import java.awt.event.*; 3 import java.io.*; 4 import java.net.*; 5  6 public class ChatClient extends Frame { 7     Socket s = null; 8  9     TextField tfTxt = new TextField();10 11     TextArea taContent = new TextArea();12 13     public static void main(String[] args) {14         new ChatClient().launchFrame(); 15     }16 17     /**18      * Version 0.619      */20     public void launchFrame() {21         setLocation(400, 300);22         this.setSize(300, 300);23         add(tfTxt, BorderLayout.SOUTH);24         add(taContent, BorderLayout.NORTH);25         pack();26         this.addWindowListener(new WindowAdapter() {27 28             @Override29             public void windowClosing(WindowEvent arg0) {30                 System.exit(0);31             }32             33         });34         tfTxt.addActionListener(new TFListener());35         setVisible(true);36         connect();37     }38     39     public void connect() {40         try {41             s = new Socket("127.0.0.1", 8888);42 System.out.println("connected!");43         } catch (UnknownHostException e) {44             e.printStackTrace();45         } catch (IOException e) {46             e.printStackTrace();47         }48         49     }50     51     private class TFListener implements ActionListener {52 53         public void actionPerformed(ActionEvent e) {54             String str = tfTxt.getText().trim();55             taContent.setText(str);56             tfTxt.setText("");57             58             try {59                 DataOutputStream dos = new DataOutputStream(s.getOutputStream());60                 dos.writeUTF(str);61                 dos.flush();62                 dos.close();63             } catch (IOException e1) {64                 e1.printStackTrace();65             }66             67         }68         69     }70 71 }
View Code

Server

1 import java.io.*; 2 import java.net.*; 3  4 public class ChatServer { 5  6     public static void main(String[] args) { 7         try { 8             // 服务器端需要创建监听端口的 ServerSocket, ServerSocket 负责接收客户连接请求 9             ServerSocket ss = new ServerSocket(8888);10             while (true) {11                 //服务器端应对客户端的每一个连接建立一个新的Socket(重要)12                 Socket s = ss.accept();13                 // 当有客户端连接上时,打印连接信息14                 System.out.println("a client connected!");15 16                 //获取Socket s的输入流17                 DataInputStream dis = new DataInputStream(s.getInputStream());18                 //获取输入流中的信息19                 String str = dis.readUTF();20                 System.out.println(str);21                 //关闭流操作22                 dis.close();23             }24         } catch (IOException e) {25             e.printStackTrace();26         }27     }28 29 }
View Code

我们此时客户端输入的内容可以显示在Server端的控制台上,每个连接上的Client的输入只有第一次输入可以显示在控制台,每个客户端不可以接收其他客户端的信息。并且当我们某些关闭处于连接状态的客户端的时候Server端会报Socket异常;

版本0.7

ChatClient

1 import java.awt.*; 2 import java.awt.event.*; 3 import java.io.DataOutputStream; 4 import java.io.IOException; 5 import java.net.*; 6  7 public class ChatClient extends Frame { 8  9     // 暴露Socket10     Socket s = null;11     TextField tfTxt = new TextField();12     TextArea taContent = new TextArea();13 14     public static void main(String[] args) {15         new ChatClient().launchFrame();16     }17 18     /**19      * Version 0.720      */21     public void launchFrame() {22         // 设置Frame位置23         setLocation(400, 300);24         // 设置Frame大小25         this.setSize(300, 300);26         // 将输入框TextField加到Frame中,并放置到Frame布局的上面27         add(tfTxt, BorderLayout.SOUTH);28         // 将显示框TextArea加到Frame中,并放置到Frame布局的下面29         add(taContent, BorderLayout.NORTH);30         // 调整布局,处理多余空白框31         pack();32         // 添加窗口监听33         this.addWindowListener(new WindowAdapter() {34 35             @Override36             public void windowClosing(WindowEvent e) {37                 System.exit(0);38             }39         });40 41         // 将监听器类TFListener添加到输入框TextField中42         tfTxt.addActionListener(new TFListener());43         // 窗口可见44         setVisible(true);45         connect();46     }47 48     // 建立連接的方法49     public void connect() {50         try {51             s = new Socket("127.0.0.1", 8888);52             System.out.println("connected!");53         } catch (UnknownHostException e) {54             e.printStackTrace();55         } catch (IOException e) {56             e.printStackTrace();57         }58     }59 60     // 建立私有的监听器类,TextField监听:将TextField内容放置到TextArea61     private class TFListener implements ActionListener {62 63         @Override64         public void actionPerformed(ActionEvent e) {65             // 获得输入框的内容,并去除两端的空格66             String string = tfTxt.getText().trim();67             // 将获取的输入内容放置到TextArea中68             taContent.setText(string);69             // 每次输入结束,将输入框置空70             tfTxt.setText("");71             try {72                 System.out.println(s);73                 DataOutputStream dos = new DataOutputStream(s.getOutputStream());74                 dos.writeUTF(string);75                 dos.flush();76                 dos.close();77             } catch (IOException e1) {78                 e1.printStackTrace();79             }80 81         }82     }83 }
View Code

Server

1 import java.io.DataInputStream; 2 import java.io.IOException; 3 import java.net.*; 4  5 //server端 6 public class ChatServer { 7  8     /** 9      * @param args10      */11     public static void main(String[] args) {12         try {13             ServerSocket ss = new ServerSocket(8888);14             while(true){15                 Socket s=ss.accept();16 System.out.println("a clint connected");17             DataInputStream dis=new DataInputStream(s.getInputStream());18             String str=dis.readUTF();19             System.out.println(str);20             dis.close();21             }22         } catch (IOException e) {23             e.printStackTrace();24         }25     }26 27 }
View Code

相较于版本0.6,做了一些调试工作,每次打印System.out.println(s);观察出错信息,关闭客户端时,仍然会出现Socket is closed异常

版本0.8

ChatClient

1 import java.awt.*; 2 import java.awt.event.*; 3 import java.io.DataOutputStream; 4 import java.io.IOException; 5 import java.net.*; 6 public class ChatClient extends Frame { 7  8     //暴露Socket 9     Socket s=null;10     DataOutputStream dos=null;11     TextField tfTxt = new TextField();12     TextArea taContent = new TextArea();13 14     public static void main(String[] args) {15         new ChatClient().launchFrame();16     }17 18     /**19      * Version 0.820      */21     public void launchFrame() {22         // 设置Frame位置23         setLocation(400, 300);24         // 设置Frame大小25         this.setSize(300, 300);26         // 将输入框TextField加到Frame中,并放置到Frame布局的上面27         add(tfTxt, BorderLayout.SOUTH);28         // 将显示框TextArea加到Frame中,并放置到Frame布局的下面29         add(taContent, BorderLayout.NORTH);30         // 调整布局,处理多余空白框31         pack();32         // 添加窗口监听33         this.addWindowListener(new WindowAdapter() {34 35             @Override36             public void windowClosing(WindowEvent e) {37                 //窗口关闭的时候释放连接资源38                 disconnect();39                 System.exit(0);40             }41         });42 43         // 将监听器类TFListener添加到输入框TextField中44         tfTxt.addActionListener(new TFListener());45         // 窗口可见46         setVisible(true);47         connect();48     }49     //建立連接的方法50     public void connect(){51         try {52             s=new Socket("127.0.0.1",8888);53             dos=new DataOutputStream(s.getOutputStream());54 System.out.println("connected!");            55         } catch (UnknownHostException e) {56             e.printStackTrace();57         } catch (IOException e) {58             e.printStackTrace();59         }60     }61     public void disconnect(){62         try {63             dos.close();64             s.close();65         } catch (Exception e) {66             e.printStackTrace();67         }68     }69 70     // 建立私有的监听器类,TextField监听:将TextField内容放置到TextArea71     private class TFListener implements ActionListener {72 73         @Override74         public void actionPerformed(ActionEvent e) {75             // 获得输入框的内容,并去除两端的空格76             String string = tfTxt.getText().trim();77             // 将获取的输入内容放置到TextArea中78             taContent.setText(string);79             // 每次输入结束,将输入框置空80             tfTxt.setText("");81             try {82 System.out.println(s);        83 //不同每次都获取一次连接84 //                DataOutputStream dos=new DataOutputStream(s.getOutputStream());85                 dos.writeUTF(string);86                 dos.flush();87 //                dos.close();88             } catch (IOException e1) {89                 e1.printStackTrace();90             }91             92         }93     }94 }
View Code

Server

1 import java.io.DataInputStream; 2 import java.io.IOException; 3 import java.net.*; 4  5 //server端 6 public class ChatServer { 7  8     public static void main(String[] args) { 9         //服务器端是否已经启动10         boolean started=false;11         try {12             ServerSocket ss = new ServerSocket(8888);13             //服务器端启动以后,started=true14             started=true;15             //服务器端启动以后才能不断接收客户端的连接16             while(started){17                 //定义boolean类型的变量,客户端时候建立连接18                 boolean bConnected;19                 Socket s=ss.accept();20 System.out.println("a clint connected");21             //客户端时候建立连接以后,bConnected=true;22             bConnected=true; 23             DataInputStream dis=new DataInputStream(s.getInputStream());24             //客户端建立连接以后,不断的接收写来的数据25             while(bConnected){        26                 String str=dis.readUTF();27                 System.out.println(str);28             }29             //没有连接上,关闭dis,释放资源30             dis.close();31             }32         } catch (IOException e) {33             e.printStackTrace();34         }35     }36 37 }
View Code

我们在这一版本中添加了连接标志,运行测试发现Server端可以接收多个客户端的连接,但是只能将第一个连接的客户端的输入显示在控制台,其他客户端依然无法获取到其他客户端的内容,仍会出现异常

版本0.9

ChatClient

1 import java.awt.*; 2 import java.awt.event.*; 3 import java.io.DataOutputStream; 4 import java.io.IOException; 5 import java.net.*; 6 public class ChatClient extends Frame { 7  8     //暴露Socket 9     Socket s=null;10     DataOutputStream dos=null;11     TextField tfTxt = new TextField();12     TextArea taContent = new TextArea();13 14     public static void main(String[] args) {15         new ChatClient().launchFrame();16     }17 18     /**19      * Version 0.920      */21     public void launchFrame() {22         // 设置Frame位置23         setLocation(400, 300);24         // 设置Frame大小25         this.setSize(300, 300);26         // 将输入框TextField加到Frame中,并放置到Frame布局的上面27         add(tfTxt, BorderLayout.SOUTH);28         // 将显示框TextArea加到Frame中,并放置到Frame布局的下面29         add(taContent, BorderLayout.NORTH);30         // 调整布局,处理多余空白框31         pack();32         // 添加窗口监听33         this.addWindowListener(new WindowAdapter() {34 35             @Override36             public void windowClosing(WindowEvent e) {37                 //窗口关闭的时候释放连接资源38                 disconnect();39                 System.exit(0);40             }41         });42 43         // 将监听器类TFListener添加到输入框TextField中44         tfTxt.addActionListener(new TFListener());45         // 窗口可见46         setVisible(true);47         connect();48     }49     //建立連接的方法50     public void connect(){51         try {52             s=new Socket("127.0.0.1",8888);53             dos=new DataOutputStream(s.getOutputStream());54 System.out.println("connected!");            55         } catch (UnknownHostException e) {56             e.printStackTrace();57         } catch (IOException e) {58             e.printStackTrace();59         }60     }61     public void disconnect(){62         try {63             dos.close();64             s.close();65         } catch (Exception e) {66             e.printStackTrace();67         }68     }69 70     // 建立私有的监听器类,TextField监听:将TextField内容放置到TextArea71     private class TFListener implements ActionListener {72 73         @Override74         public void actionPerformed(ActionEvent e) {75             // 获得输入框的内容,并去除两端的空格76             String string = tfTxt.getText().trim();77             // 将获取的输入内容放置到TextArea中78             taContent.setText(string);79             // 每次输入结束,将输入框置空80             tfTxt.setText("");81             try {82 System.out.println(s);        83 //不同每次都获取一次连接84 //                DataOutputStream dos=new DataOutputStream(s.getOutputStream());85                 dos.writeUTF(string);86                 dos.flush();87 //                dos.close();88             } catch (IOException e1) {89                 e1.printStackTrace();90             }91             92         }93     }94 }
View Code

Server

1 import java.io.DataInputStream; 2 import java.io.EOFException; 3 import java.io.IOException; 4 import java.net.*; 5  6 //server端 7 public class ChatServer { 8  9     public static void main(String[] args) {10         //服务器端是否已经启动11         boolean started=false;12         ServerSocket ss = null;13         Socket s=null;14         DataInputStream dis=null;15         try {16             //可能会产生端口绑定异常17             ss = new ServerSocket(8888);18         }catch(BindException e){19             System.out.println("端口使用中");20             System.out.println("关闭相关程序,并重新运行");21             System.exit(0);22         }catch(IOException e){23             e.printStackTrace();24         }25         try {26             //服务器端启动以后,started=true27             started=true;28             //服务器端启动以后才能不断接收客户端的连接29             while(started){30                 //定义boolean类型的变量,客户端时候建立连接31                 boolean bConnected;32                 s=ss.accept();33 System.out.println("a clint connected");34             //客户端时候建立连接以后,bConnected=true;35             bConnected=true; 36             dis=new DataInputStream(s.getInputStream());37             //客户端建立连接以后,不断的接收写来的数据38             while(bConnected){39                 //readUTF是阻塞式的40                 String str=dis.readUTF();41                 System.out.println(str);42             }43             //没有连接上,关闭dis,释放资源44 //            dis.close();45             }46             //如果是因为客户端的关闭而导致的连接中断,则做这样的处理47         }catch(EOFException e){48             System.out.println("Client closed");49         //其他异常,直接打印异常信息50         }catch (IOException e) {51             e.printStackTrace();52         }finally{53             try {54                 if(dis!=null){    55                     dis.close();56                 }57                 if(s!=null){    58                     s.close();59                 }60             } catch (IOException e1) {61                 e1.printStackTrace();62             }63         }64     }65 66 }
View Code

之前的版本,当我们关闭客户端的时候都会发生异常,在这个版本中我们做了相应的处理,去捕获这个异常,并将连接资源的关闭工作进行细化;这里我们在客户端进行了处理:将DataOutputStream提到了全局变量的位置。不用每次都去获取一次Socket的输出流;

版本1.0

ChatClient

1 import java.awt.*; 2 import java.awt.event.*; 3 import java.io.DataOutputStream; 4 import java.io.IOException; 5 import java.net.*; 6  7 public class ChatClient extends Frame { 8  9     // 暴露Socket10     Socket s = null;11     DataOutputStream dos = null;12     TextField tfTxt = new TextField();13     TextArea taContent = new TextArea();14 15     public static void main(String[] args) {16         new ChatClient().launchFrame();17     }18 19     /**20      * Version 1.021      */22     public void launchFrame() {23         // 设置Frame位置24         setLocation(400, 300);25         // 设置Frame大小26         this.setSize(300, 300);27         // 将输入框TextField加到Frame中,并放置到Frame布局的上面28         add(tfTxt, BorderLayout.SOUTH);29         // 将显示框TextArea加到Frame中,并放置到Frame布局的下面30         add(taContent, BorderLayout.NORTH);31         // 调整布局,处理多余空白框32         pack();33         // 添加窗口监听34         this.addWindowListener(new WindowAdapter() {35 36             @Override37             public void windowClosing(WindowEvent e) {38                 // 窗口关闭的时候释放连接资源39                 disconnect();40                 System.exit(0);41             }42         });43 44         // 将监听器类TFListener添加到输入框TextField中45         tfTxt.addActionListener(new TFListener());46         // 窗口可见47         setVisible(true);48         connect();49     }50 51     // 建立連接的方法52     public void connect() {53         try {54             s = new Socket("127.0.0.1", 8888);55             dos = new DataOutputStream(s.getOutputStream());56             System.out.println("connected!");57         } catch (UnknownHostException e) {58             e.printStackTrace();59         } catch (IOException e) {60             e.printStackTrace();61         }62     }63 64     public void disconnect() {65         try {66             dos.close();67             s.close();68         } catch (Exception e) {69             e.printStackTrace();70         }71     }72 73     // 建立私有的监听器类,TextField监听:将TextField内容放置到TextArea74     private class TFListener implements ActionListener {75 76         @Override77         public void actionPerformed(ActionEvent e) {78             // 获得输入框的内容,并去除两端的空格79             String string = tfTxt.getText().trim();80             // 将获取的输入内容放置到TextArea中81             taContent.setText(string);82             // 每次输入结束,将输入框置空83             tfTxt.setText("");84             try {85                 System.out.println(s);86                 // 不同每次都获取一次连接87                 // DataOutputStream dos=new88                 // DataOutputStream(s.getOutputStream());89                 dos.writeUTF(string);90                 dos.flush();91                 // dos.close();92             } catch (IOException e1) {93                 e1.printStackTrace();94             }95 96         }97     }98 }
View Code

Server

1 import java.io.DataInputStream; 2 import java.io.EOFException; 3 import java.io.IOException; 4 import java.net.*; 5 import java.security.Principal; 6  7 //server端 8 public class ChatServer { 9 10     boolean started = false;11     ServerSocket ss = null;12 13     public static void main(String[] args) {14         new ChatServer().start();15     }16 17     public void start() {18 19         try {20             // 可能会产生端口绑定异常21             ss = new ServerSocket(8888);22             // 服务器端启动以后,started=true23             started = true;24         } catch (BindException e) {25             System.out.println("端口使用中");26             System.out.println("关闭相关程序,并重新运行");27             System.exit(0);28         } catch (IOException e) {29             e.printStackTrace();30         }31         try {32             // 服务器端启动以后才能不断接收客户端的连接33             while (started) {34                 Socket s = ss.accept();35                 // 不能在静态方法里new一个动态的类36                 Client c = new Client(s);37                 System.out.println("a clint connected");38                 new Thread(c).start();39             }40             // 如果是因为客户端的关闭而导致的连接中断,则做这样的处理41         } catch (IOException e) {42             e.printStackTrace();43 44         } finally {45             try {46                 ss.close();47             } catch (IOException e) {48                 e.printStackTrace();49             }50         }51     }52 53 }54 55 class Client implements Runnable {56     private Socket s;57     private DataInputStream dis = null;58     private boolean bConnected = false;59 60     public Client(Socket s) {61         this.s = s;62         try {63             dis = new DataInputStream(s.getInputStream());64             bConnected = true;65         }catch (IOException e) {66             e.printStackTrace();67 68         }69     }70 71     @Override72     public void run() {73         try {74             while (bConnected) {75                 String str = dis.readUTF();76                 System.out.println(str);77             }78         } catch (EOFException e) {79             System.out.println("Client closed");80         } catch (IOException e) {81             e.printStackTrace();82         } finally {83             try {84                 if (dis != null) {85                     dis.close();86                 }87                 if (s != null) {88                     s.close();89                 }90             } catch (Exception e2) {91                 e2.printStackTrace();92             }93         }94 95     }96 97 }
View Code

版本1.0可以处理多个客户端同时连接并显示其输入内容的效果;将每个客户端封装到一个独立的线程中;

版本1.1

ChatClient

1 import java.awt.*;  2 import java.awt.event.*;  3 import java.io.DataOutputStream;  4 import java.io.IOException;  5 import java.net.*;  6 import java.util.*;  7 import java.util.List;  8 //转发给  9 public class ChatClient extends Frame { 10  11     // 暴露Socket 12     Socket s = null; 13     DataOutputStream dos = null; 14     TextField tfTxt = new TextField(); 15     TextArea taContent = new TextArea(); 16  17     public static void main(String[] args) { 18         new ChatClient().launchFrame(); 19     } 20  21     /** 22      * Version 1.1:转发给其他客户端,保存socket连接,用集合 23      */ 24     public void launchFrame() { 25         // 设置Frame位置 26         setLocation(400, 300); 27         // 设置Frame大小 28         this.setSize(300, 300); 29         // 将输入框TextField加到Frame中,并放置到Frame布局的上面 30         add(tfTxt, BorderLayout.SOUTH); 31         // 将显示框TextArea加到Frame中,并放置到Frame布局的下面 32         add(taContent, BorderLayout.NORTH); 33         // 调整布局,处理多余空白框 34         pack(); 35         // 添加窗口监听 36         this.addWindowListener(new WindowAdapter() { 37  38             @Override 39             public void windowClosing(WindowEvent e) { 40                 // 窗口关闭的时候释放连接资源 41                 disconnect(); 42                 System.exit(0); 43             } 44         }); 45  46         // 将监听器类TFListener添加到输入框TextField中 47         tfTxt.addActionListener(new TFListener()); 48         // 窗口可见 49         setVisible(true); 50         connect(); 51     } 52  53     // 建立連接的方法 54     public void connect() { 55         try { 56             s = new Socket("127.0.0.1", 8888); 57             dos = new DataOutputStream(s.getOutputStream()); 58             System.out.println("connected!"); 59         } catch (UnknownHostException e) { 60             e.printStackTrace(); 61         } catch (IOException e) { 62             e.printStackTrace(); 63         } 64     } 65  66     public void disconnect() { 67         try { 68             dos.close(); 69             s.close(); 70         } catch (Exception e) { 71             e.printStackTrace(); 72         } 73     } 74  75     // 建立私有的监听器类,TextField监听:将TextField内容放置到TextArea 76     private class TFListener implements ActionListener { 77  78         @Override 79         public void actionPerformed(ActionEvent e) { 80             // 获得输入框的内容,并去除两端的空格 81             String string = tfTxt.getText().trim(); 82             // 将获取的输入内容放置到TextArea中 83             taContent.setText(string); 84             // 每次输入结束,将输入框置空 85             tfTxt.setText(""); 86             try { 87                 System.out.println(s); 88                 // 不同每次都获取一次连接 89                 // DataOutputStream dos=new 90                 // DataOutputStream(s.getOutputStream()); 91                 dos.writeUTF(string); 92                 dos.flush(); 93                 // dos.close(); 94             } catch (IOException e1) { 95                 e1.printStackTrace(); 96             } 97  98         } 99     }100 }
View Code

Server

1 import java.io.DataInputStream;  2 import java.io.DataOutputStream;  3 import java.io.EOFException;  4 import java.io.IOException;  5 import java.net.*;  6 import java.security.Principal;  7 import java.util.ArrayList;  8 import java.util.List;  9  10 //server端 11 public class ChatServer { 12  13     boolean started = false; 14     ServerSocket ss = null; 15     List
clients = new ArrayList
(); 16 17 public static void main(String[] args) { 18 new ChatServer().start(); 19 } 20 21 public void start() { 22 23 try { 24 // 可能会产生端口绑定异常 25 ss = new ServerSocket(8888); 26 // 服务器端启动以后,started=true 27 started = true; 28 } catch (BindException e) { 29 System.out.println("端口使用中"); 30 System.out.println("关闭相关程序,并重新运行"); 31 System.exit(0); 32 } catch (IOException e) { 33 e.printStackTrace(); 34 } 35 try { 36 // 服务器端启动以后才能不断接收客户端的连接 37 while (started) { 38 Socket s = ss.accept(); 39 // 不能在静态方法里new一个动态的类 40 Client c = new Client(s); 41 System.out.println("a clint connected"); 42 new Thread(c).start(); 43 clients.add(c); 44 } 45 // 如果是因为客户端的关闭而导致的连接中断,则做这样的处理 46 } catch (IOException e) { 47 e.printStackTrace(); 48 49 } finally { 50 try { 51 ss.close(); 52 } catch (IOException e) { 53 e.printStackTrace(); 54 } 55 } 56 } 57 58 class Client implements Runnable { 59 private Socket s; 60 private DataInputStream dis = null; 61 private DataOutputStream dos = null; 62 private boolean bConnected = false; 63 64 public Client(Socket s) { 65 this.s = s; 66 try { 67 dis = new DataInputStream(s.getInputStream()); 68 dos = new DataOutputStream(s.getOutputStream()); 69 bConnected = true; 70 } catch (IOException e) { 71 e.printStackTrace(); 72 73 } 74 } 75 76 // 发送的方法 77 public void send(String str) { 78 try { 79 dos.writeUTF(str); 80 } catch (IOException e) { 81 e.printStackTrace(); 82 } 83 } 84 85 @Override 86 public void run() { 87 try { 88 while (bConnected) { 89 String str = dis.readUTF(); 90 System.out.println(str); 91 for(int i=0;i
View Code

将每个连接上的客户端Client添加到我们的List集合中,方便我们将我们的输入内容发送到List集合保存的Client;

版本1.2

ChatClient

1 import java.awt.BorderLayout;  2 import java.awt.Frame;  3 import java.awt.TextArea;  4 import java.awt.TextField;  5 import java.awt.event.ActionEvent;  6 import java.awt.event.ActionListener;  7 import java.awt.event.WindowAdapter;  8 import java.awt.event.WindowEvent;  9 import java.io.DataInputStream; 10 import java.io.DataOutputStream; 11 import java.io.IOException; 12 import java.net.Socket; 13 import java.net.SocketException; 14 import java.net.UnknownHostException; 15  16 //转发给 17 public class ChatClient extends Frame { 18  19     // 暴露Socket 20     Socket s = null; 21     DataOutputStream dos = null; 22     DataInputStream dis = null; 23     private boolean bConnected = false; 24     TextField tfTxt = new TextField(); 25     TextArea taContent = new TextArea(); 26  27     Thread tRecv=new Thread(new RecvThread()); 28     public static void main(String[] args) { 29         new ChatClient().launchFrame(); 30     } 31  32     /** 33      * Version 1.2 34      */ 35     public void launchFrame() { 36         // 设置Frame位置 37         setLocation(400, 300); 38         // 设置Frame大小 39         this.setSize(300, 300); 40         // 将输入框TextField加到Frame中,并放置到Frame布局的上面 41         add(tfTxt, BorderLayout.SOUTH); 42         // 将显示框TextArea加到Frame中,并放置到Frame布局的下面 43         add(taContent, BorderLayout.NORTH); 44         // 调整布局,处理多余空白框 45         pack(); 46         // 添加窗口监听 47         this.addWindowListener(new WindowAdapter() { 48  49             @Override 50             public void windowClosing(WindowEvent e) { 51                 // 窗口关闭的时候释放连接资源 52                 disconnect(); 53                 System.exit(0); 54             } 55         }); 56  57         // 将监听器类TFListener添加到输入框TextField中 58         tfTxt.addActionListener(new TFListener()); 59         // 窗口可见 60         setVisible(true); 61         connect(); 62          63         tRecv.start(); 64     } 65  66     // 建立连接的方法 67     public void connect() { 68         try { 69             s = new Socket("127.0.0.1", 8888); 70             dos = new DataOutputStream(s.getOutputStream()); 71             dis = new DataInputStream(s.getInputStream()); 72             System.out.println("connected!"); 73             bConnected = true; 74         } catch (UnknownHostException e) { 75             e.printStackTrace(); 76         } catch (IOException e) { 77             e.printStackTrace(); 78         } 79     } 80  81     public void disconnect() { 82         try { 83             dos.close(); 84             dis.close(); 85             s.close(); 86         } catch (IOException e) { 87             e.printStackTrace(); 88         } 89     /*    try { 90             bConnected=false; 91             tRecv.join(); 92         } catch(InterruptedException e){ 93             e.printStackTrace(); 94         } finally{ 95             try { 96                 dos.close(); 97                 dis.close(); 98                 s.close(); 99             } catch (IOException e) {100                 e.printStackTrace();101             }102             103         }*/104     }105 106     private class RecvThread implements Runnable {107 108         @Override109         public void run() {110             try {111                 while (bConnected) {112                     String str = dis.readUTF();113 //                    System.out.println(str);114                     taContent.setText(taContent.getText()+str+"\n");115                 }116             }catch(SocketException e){117                 System.out.println("退出!over");118             }catch (IOException e) {119                 e.printStackTrace();120             }121         }122     }123 124     // 建立私有的监听器类,TextField监听:将TextField内容放置到TextArea125     private class TFListener implements ActionListener {126 127         @Override128         public void actionPerformed(ActionEvent e) {129             // 获得输入框的内容,并去除两端的空格130             String string = tfTxt.getText().trim();131             // 将获取的输入内容放置到TextArea中132             taContent.setText(string);133             // 每次输入结束,将输入框置空134             tfTxt.setText("");135             try {136                 System.out.println(s);137                 // 不同每次都获取一次连接138                 // DataOutputStream dos=new139                 // DataOutputStream(s.getOutputStream());140                 dos.writeUTF(string);141                 dos.flush();142                 // dos.close();143             } catch (IOException e1) {144                 e1.printStackTrace();145             }146 147         }148     }149 }
View Code

Server

1 import java.io.DataInputStream;  2 import java.io.DataOutputStream;  3 import java.io.EOFException;  4 import java.io.IOException;  5 import java.net.BindException;  6 import java.net.ServerSocket;  7 import java.net.Socket;  8 import java.util.ArrayList;  9 import java.util.List; 10  11 //server端 12 public class ChatServer { 13  14     boolean started = false; 15     ServerSocket ss = null; 16     List
clients = new ArrayList
(); 17 18 public static void main(String[] args) { 19 new ChatServer().start(); 20 } 21 22 public void start() { 23 24 try { 25 // 可能会产生端口绑定异常 26 ss = new ServerSocket(8888); 27 // 服务器端启动以后,started=true 28 started = true; 29 } catch (BindException e) { 30 System.out.println("端口使用中"); 31 System.out.println("关闭相关程序,并重新运行"); 32 System.exit(0); 33 } catch (IOException e) { 34 e.printStackTrace(); 35 } 36 try { 37 // 服务器端启动以后才能不断接收客户端的连接 38 while (started) { 39 Socket s = ss.accept(); 40 // 不能在静态方法里new一个动态的类 41 Client c = new Client(s); 42 System.out.println("a clint connected"); 43 new Thread(c).start(); 44 clients.add(c); 45 } 46 // 如果是因为客户端的关闭而导致的连接中断,则做这样的处理 47 } catch (IOException e) { 48 e.printStackTrace(); 49 50 } finally { 51 try { 52 ss.close(); 53 } catch (IOException e) { 54 e.printStackTrace(); 55 } 56 } 57 } 58 59 class Client implements Runnable { 60 private Socket s; 61 private DataInputStream dis = null; 62 private DataOutputStream dos = null; 63 private boolean bConnected = false; 64 65 public Client(Socket s) { 66 this.s = s; 67 try { 68 dis = new DataInputStream(s.getInputStream()); 69 dos = new DataOutputStream(s.getOutputStream()); 70 bConnected = true; 71 } catch (IOException e) { 72 e.printStackTrace(); 73 74 } 75 } 76 77 // 发送的方法 78 public void send(String str) { 79 try { 80 dos.writeUTF(str); 81 } catch (IOException e) { 82 e.printStackTrace(); 83 } 84 } 85 86 @Override 87 public void run() { 88 try { 89 while (bConnected) { 90 String str = dis.readUTF(); 91 System.out.println(str); 92 for(int i=0;i
View Code

此时我们已经可以实现我们的预期功能了,不同的客户端可以进行通信了;

版本1.3

ChatClient

1 import java.awt.*;  2 import java.awt.event.*;  3 import java.io.*;  4 import java.net.*;  5   6 public class ChatClient extends Frame {  7     Socket s = null;  8     DataOutputStream dos = null;  9     DataInputStream dis = null; 10     private boolean bConnected = false; 11  12     TextField tfTxt = new TextField(); 13  14     TextArea taContent = new TextArea(); 15  16     Thread tRecv = new Thread(new RecvThread()); 17  18     public static void main(String[] args) { 19         new ChatClient().launchFrame(); 20     } 21  22     public void launchFrame() { 23         setLocation(400, 300); 24         this.setSize(300, 300); 25         add(tfTxt, BorderLayout.SOUTH); 26         add(taContent, BorderLayout.NORTH); 27         pack(); 28         this.addWindowListener(new WindowAdapter() { 29  30             @Override 31             public void windowClosing(WindowEvent arg0) { 32                 disconnect(); 33                 System.exit(0); 34             } 35  36         }); 37         tfTxt.addActionListener(new TFListener()); 38         setVisible(true); 39         connect(); 40  41         tRecv.start(); 42     } 43  44     public void connect() { 45         try { 46             s = new Socket("127.0.0.1", 8888); 47             dos = new DataOutputStream(s.getOutputStream()); 48             dis = new DataInputStream(s.getInputStream()); 49             System.out.println("connected!"); 50             bConnected = true; 51         } catch (UnknownHostException e) { 52             e.printStackTrace(); 53         } catch (IOException e) { 54             e.printStackTrace(); 55         } 56  57     } 58  59     public void disconnect() { 60         try { 61             dos.close(); 62             dis.close(); 63             s.close(); 64         } catch (IOException e) { 65             e.printStackTrace(); 66         } 67  68         /* 69          * try { bConnected = false; tRecv.join(); } catch(InterruptedException 70          * e) { e.printStackTrace(); } finally { try { dos.close(); dis.close(); 71          * s.close(); } catch (IOException e) { e.printStackTrace(); } } 72          */ 73     } 74  75     private class TFListener implements ActionListener { 76  77         public void actionPerformed(ActionEvent e) { 78             String str = tfTxt.getText().trim(); 79             // taContent.setText(str); 80             tfTxt.setText(""); 81  82             try { 83                 // System.out.println(s); 84                 dos.writeUTF(str); 85                 dos.flush(); 86                 // dos.close(); 87             } catch (IOException e1) { 88                 e1.printStackTrace(); 89             } 90  91         } 92  93     } 94  95     private class RecvThread implements Runnable { 96  97         public void run() { 98             try { 99                 while (bConnected) {100                     String str = dis.readUTF();101                     // System.out.println(str);102                     taContent.setText(taContent.getText() + str + '\n');103                 }104             } catch (SocketException e) {105                 System.out.println("退出了,bye!");106             } catch (EOFException e) {107                 System.out.println("推出了,bye - bye!");108             } catch (IOException e) {109                 e.printStackTrace();110             }111 112         }113 114     }115 }
View Code

Server

1 import java.io.*;  2 import java.net.*;  3 import java.util.*;  4   5 public class ChatServer {  6     boolean started = false;  7     ServerSocket ss = null;  8   9     List
clients = new ArrayList
(); 10 11 public static void main(String[] args) { 12 new ChatServer().start(); 13 } 14 15 public void start() { 16 try { 17 ss = new ServerSocket(8888); 18 started = true; 19 } catch (BindException e) { 20 System.out.println("端口使用中...."); 21 System.out.println("请关掉相关程序并重新运行服务器!"); 22 System.exit(0); 23 } catch (IOException e) { 24 e.printStackTrace(); 25 } 26 27 try { 28 29 while (started) { 30 Socket s = ss.accept(); 31 Client c = new Client(s); 32 System.out.println("a client connected!"); 33 new Thread(c).start(); 34 clients.add(c); 35 // dis.close(); 36 } 37 } catch (IOException e) { 38 e.printStackTrace(); 39 } finally { 40 try { 41 ss.close(); 42 } catch (IOException e) { 43 // TODO Auto-generated catch block 44 e.printStackTrace(); 45 } 46 } 47 } 48 49 class Client implements Runnable { 50 private Socket s; 51 private DataInputStream dis = null; 52 private DataOutputStream dos = null; 53 private boolean bConnected = false; 54 55 public Client(Socket s) { 56 this.s = s; 57 try { 58 dis = new DataInputStream(s.getInputStream()); 59 dos = new DataOutputStream(s.getOutputStream()); 60 bConnected = true; 61 } catch (IOException e) { 62 e.printStackTrace(); 63 } 64 } 65 66 public void send(String str) { 67 try { 68 dos.writeUTF(str); 69 } catch (IOException e) { 70 clients.remove(this); 71 System.out.println("对方退出了!我从List里面去掉了!"); 72 // e.printStackTrace(); 73 } 74 } 75 76 public void run() { 77 try { 78 while (bConnected) { 79 String str = dis.readUTF(); 80 System.out.println(str); 81 for (int i = 0; i < clients.size(); i++) { 82 Client c = clients.get(i); 83 c.send(str); 84 // System.out.println(" a string send !"); 85 } 86 /* 87 * for(Iterator
it = clients.iterator(); 88 * it.hasNext(); ) { Client c = it.next(); c.send(str); } 89 */ 90 /* 91 * Iterator
it = clients.iterator(); 92 * while(it.hasNext()) { Client c = it.next(); c.send(str); 93 * } 94 */ 95 } 96 } catch (EOFException e) { 97 System.out.println("Client closed!"); 98 } catch (IOException e) { 99 e.printStackTrace();100 } finally {101 try {102 if (dis != null)103 dis.close();104 if (dos != null)105 dos.close();106 if (s != null) {107 s.close();108 // s = null;109 }110 111 } catch (IOException e1) {112 e1.printStackTrace();113 }114 115 }116 }117 118 }119 }
View Code

对程序出现的一些bug进行了修复,细化了关闭连接资源等操作,可以根据每个版本的差异梳理清楚代码的编写过程;

 

转载于:https://www.cnblogs.com/ysw-go/p/5499630.html

你可能感兴趣的文章
pig自定义UDF
查看>>
spring security 11种过滤器介绍
查看>>
代码实现导航栏分割线
查看>>
大数据学习系列(8)-- WordCount+Block+Split+Shuffle+Map+Reduce技术详解
查看>>
【AS3代码】播放FLV视频流的三步骤!
查看>>
枚举的使用
查看>>
luogu4849 寻找宝藏 (cdq分治+dp)
查看>>
日志框架--(一)基础篇
查看>>
关于源程序到可运行程序的过程
查看>>
转载:mysql数据库密码忘记找回方法
查看>>
scratch少儿编程第一季——06、人在江湖混,没有背景怎么行。
查看>>
【贪心+DFS】D. Field expansion
查看>>
C# Async与Await的使用
查看>>
Mysql性能调优
查看>>
iOS基础-UIKit框架-多控制器管理-实例:qq界面框架
查看>>
自定义tabbar(纯代码)
查看>>
小程序底部导航栏
查看>>
poj1611 简单并查集
查看>>
Ubuntu 14.04下安装CUDA8.0
查看>>
跨平台开发 -- C# 使用 C/C++ 生成的动态链接库
查看>>