import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; import java.io.IOException; import java.net.BindException; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class ChatServer { /** * 8.2、接收多个信息,建立两个条件判断 */ boolean started = false; ServerSocket ss = null; List<Client> clients = new ArrayList<Client>(); public static void main(String[] args) { new ChatServer().start(); } public void start() { /** * 5、创建服务端的连接端口号ServerSocket,并接受客户端的连接accept * 打印System.out.println("a client connetion")作为测试 */ try{ ss = new ServerSocket(8888); started = true; //创建端口后为真 } catch (BindException e) { System.out.println("端口被占用"); System.out.println("请关闭程序,重启服务器"); System.exit(0); } catch (IOException e) { e.printStackTrace(); } try { while(started){ Socket s = ss.accept(); System.out.println("a client connetion"); Client c = new Client(s); new Thread(c).start(); clients.add(c); } } catch (IOException e){ e.printStackTrace(); } finally { try { ss.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * 10、建立线程处理客户端 */ class Client implements Runnable{ private Socket s; private DataInputStream dis = null; private DataOutputStream dos = null; private boolean bConnected = false; public Client(Socket s){ this.s = s; /** * 7.2、建立输入流,读取客户端输入的数据 */ try{ dis = new DataInputStream(s.getInputStream()); dos = new DataOutputStream(s.getOutputStream()); bConnected = true; //接收到连接后为真 } catch (IOException e){ e.printStackTrace(); } } /** * 11、服务端接收客户端信息并发送给客户端 */ public void send(String str) { try { dos.writeUTF(str); } catch (IOException e) { clients.remove(this); //当其中一个client退出的时候要移除list里面的内容,移除当前对象的内容,用this。 System.out.println("对方已退出!"); } } @Override public void run() { try { while(bConnected) { String str = dis.readUTF(); System.out.println(str); for(int i = 0;i<clients.size();i++){ Client c = clients.get(i); c.send(str); } /* for(Iterator<Client> it = clients.iterator();it.hasNext();) { Client c = it.next(); c.send(str); } Iterator<Client> it = clients.iterator(); while(it.hasNext()){ Client c =it.next(); c.send(str); } */ } } catch (EOFException e) { System.out.println("client closed"); } catch (IOException e){ e.printStackTrace(); /** * 9、调整bug,将程序写得更健壮,打印友好提示信息 */ } finally { try { if(dis != null){ dis.close(); } if(dos != null){ dos.close(); } if(s != null) { s.close(); } } catch (IOException e) { e.printStackTrace(); } } } } }import java.awt.BorderLayout; import java.awt.Frame; import java.awt.TextArea; import java.awt.TextField; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; import java.net.SocketException; import java.net.UnknownHostException; public class ChatClient extends Frame { Socket s = null; //成员变量,方便拿到socket里面的内容 DataOutputStream dos = null; DataInputStream dis = null; private boolean bConnected = false; Thread tRecv = new Thread(new RecvThread()); /** * 2、添加TextField文本输入框,添加TestArea下拉条 */ TextField tfTex = new TextField(); TextArea taContent = new TextArea(); public static void main(String[] args) { new ChatClient().luanchFrame(); } public void luanchFrame(){ /** * 1、首先创建窗口 */ this.setLocation(300, 400); this.setSize(400, 500); this.add(tfTex, BorderLayout.SOUTH); //两个参数,设定传入的方向,BorderLayout区域划分为:东西南北中 this.add(taContent, BorderLayout.EAST); pack(); //将区域包裹,不留空白区域 /** * 3、添加窗口关闭的功能,这里使用匿名类(没有名字的类)。(其它两种,并排的监听器类、内部类) */ this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { disconnect(); //关闭窗口的时候调用断开连接的方法 System.exit(0); } }); tfTex.addActionListener(new TFListener()); this.setVisible(true); connect(); tRecv.start(); } /** * 6、与服务器建立连接Socket(主机,端口号) * 打印一句话作为测试 */ public void connect() { try { s = new Socket("127.0.0.1",8888); dos = new DataOutputStream(s.getOutputStream()); dis = new DataInputStream(s.getInputStream()); System.out.println("connect"); bConnected = true; } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * 8.1、当连接断开的时候,关闭socket */ public void disconnect() { try { bConnected = false; dos.close(); dis.close(); s.close(); } catch (IOException e) { e.printStackTrace(); } /* try { bConnected = false; tRecv.join(); } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { dos.close(); dis.close(); s.close(); } catch (IOException e) { e.printStackTrace(); } } */ } /** * 4、将输入框的内容显示到显示区域。这里使用内部类(方便修改以及添加内容,不被其它内调用) */ private class TFListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { String str = tfTex.getText().trim(); //得到输入框的内容 // taContent.setText(str); //显示到TextArea tfTex.setText(""); //将输入框的内容输出后,设置为空 /** * 7.1、建立输出流,向服务器端写入内容 * 定义为成员变量,创建对象放到连接里,连接不断开就可以一直向服务器发送信息 */ try { dos.writeUTF(str); dos.flush(); //添加冲刷/刷新 } catch (IOException e1) { e1.printStackTrace(); } } } /** * 12、启用线程接收服务器发送的信息 */ public class RecvThread implements Runnable { @Override public void run() { try{ while(bConnected){ String str = dis.readUTF(); // System.out.println(str); taContent.setText(taContent.getText() + str +"\n"); } } catch(SocketException e) { System.out.println("a client 已退出!"); }catch(IOException e) { e.printStackTrace(); } } } }
聊天程序初级版
最新推荐文章于 2024-08-11 20:00:32 发布