java项目-----客户端与客户端通信--实现群聊功能的代码
这是这个网络聊天室项目的原理图:
很简单,首先ABCD是4个客户端,当A发送信息给服务器,服务器实现以广播的形式把信息全发给每个人---群发群聊
客户端代码:
package com.aa; import java.awt.Color; import java.awt.FlowLayout; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.io.*; import java.net.*; import java.util.Date; import java.awt.BorderLayout; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollBar; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.UIManager; public class Client { public static void initUIManager() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { System.err.println("获取系统外观失败:" + e); } } public static void main(String[] args) { initUIManager(); new ClientFrame(); } } class ClientFrame extends JFrame implements Runnable, ActionListener, KeyListener { private static final long serialVersionUID = 8518610966119429018L; ImageIcon image;// 定义一个图片 JPanel panel; JLabel label; JFrame frame;// 改变窗体的大小 JScrollPane textPane; JTextArea areaText; // 加滚动轴代码 JTextField fieldMsg; JButton butSend; JButton butConnect; Socket socket; DataInputStream in; DataOutputStream out; Thread thread; public static int WIDTH = 500; public static int HEIGHT = 400; public static String title = "Client"; private static final String IP_ADDRESS = "127.0.0.1"; public ClientFrame() { init(); setTitle("客户端"); setSize(480, 400);// setLocationRelativeTo(null); setVisible(true); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }// 首先确定插入一张图片 public void init() {// / setLayout(null); image = new ImageIcon("90.jpg");// label = new JLabel(image); label.setBounds(173, 0, 415, 324); panel = new JPanel();// areaText = new JTextArea(); this.setResizable(false); panel.add(areaText); areaText.setLineWrap(true); areaText.setEditable(false); textPane = new JScrollPane(areaText); // 客户端 (Client) (通常是一个采用图形用//界面的程序)与服务器 (Server) 区分开来。 butSend = new JButton("Send"); butSend.addKeyListener(this);// 设置按钮监听器 fieldMsg = new JTextField(150); butSend.addActionListener(this); butConnect = new JButton("Connect"); butConnect.addActionListener(this); areaText.setBackground(Color.yellow);// /该背景色 // 设置文本区域的大小 areaText.setBounds(0, 0, 287, 321);// /修改文本域的大小 textPane.setBounds(5, 5, 475, 320); fieldMsg.setBounds(5, 330, 280, 24); butSend.setBounds(299, 330, 80, 24); butConnect.setBounds(394, 330, 80, 24); add(panel); add(label, BorderLayout.EAST); add(areaText);// add(textPane);// add(butSend); add(butConnect); add(fieldMsg); Toolkit kit = Toolkit.getDefaultToolkit(); Image imge = kit.getImage("27.jpg"); this.setIconImage(imge); fieldMsg.addKeyListener(this); socket = new Socket();// 客户端对象 thread = new Thread(this); } // public void startSocket() {// (一)核心 try {// 向服务器端发送一个连接请求,跟服务器创建一个连接 if (!socket.isConnected()) {// InetAddress address = InetAddress.getByName(IP_ADDRESS); InetSocketAddress socketAddress = new InetSocketAddress(// 是.net包中的一个类 address, 4339);// 根据ip地址和端口号创建套接字地址 socket.connect(socketAddress); in = new DataInputStream(socket.getInputStream()); out = new DataOutputStream(socket.getOutputStream()); butSend.setEnabled(true); if (!(thread.isAlive())) { thread = new Thread(this); } thread.start(); } } catch (Exception e) { System.out.println(e); socket = new Socket(); } } public void send() { String msg = fieldMsg.getText().trim(); if (msg.isEmpty()) { JOptionPane.showMessageDialog(this, "Please input you message before sending."); return; } // areaText.append("Client: " + msg + "\n"); fieldMsg.setText(""); try { Date d = new Date(); out.writeUTF("\n" + msg + "\n" + d.toLocaleString());// 这是发送给服务器的 } catch (Exception e) { e.printStackTrace(); } } @Override public void actionPerformed(ActionEvent arg0) {// 使用此方法判断 if (arg0.getSource() == butSend) { send(); } else if (arg0.getSource() == butConnect) { startSocket(); } } @Override public void run() {// 这和send方法有何先后顺序,服务端程序运行后,客户端该最哪些动作,同时服务器端程序是怎样的? if (Thread.currentThread() == thread) { String msg = null; while (true) {// 循环接收服务器端发送的信息并显示在文本区 try { // /核心(二) msg = in.readUTF();// areaText.append("Client: " + msg + "\n");// 我曾修改过 } catch (IOException e) { e.printStackTrace(); socket = new Socket(); break; } } } } @Override public void keyPressed(KeyEvent arg0) { if (arg0.getKeyCode() == KeyEvent.VK_ENTER) { send(); } } @Override public void keyReleased(KeyEvent arg0) { } @Override public void keyTyped(KeyEvent arg0) { } }
服务器端代码:
package com.aa; 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.net.SocketException; import java.util.ArrayList; import java.util.List; public class Server { boolean started = false; ServerSocket ss = null; List<ChatClient> clients = new ArrayList<ChatClient>(); // 保存客户端线程类list是一个接口,Arraylist是一个类 // ArrayList是一个集合类。类里面可以放很多对象。 clients.size是指的是有多少个对象 public static void main(String[] args) { new Server().start(); } void start() { try { ss = new ServerSocket(4339); // 建立服务端对象 started = true; } catch (BindException e) {//创建对象后,需要做异常处理,以便程序出错时,做出响应 System.out.println("端口使用中"); } catch (IOException e) { e.printStackTrace();// } // 死循环 try {// 核心(一) while (started) { Socket s = ss.accept(); // 监听客户端发来的请求/ ChatClient c = new ChatClient(s); System.out.println("客戶端接收成功"); new Thread(c).start(); clients.add(c); } } catch (IOException e) { e.printStackTrace(); } finally { try { ss.close(); } catch (IOException e) { e.printStackTrace(); } } } // 这个类的作用 // 建立客户端线程接收,发送数据多线程的所以要实现Runnable接口 class ChatClient implements Runnable { private Socket s; DataInputStream dis = null; DataOutputStream dos = null; boolean bConnected = false; public ChatClient(Socket s) { this.s = s; try {// 用来接收客户端发来数据的输入流 dis = new DataInputStream(s.getInputStream()); // 服务器向客户端发送数据的输出流 dos = new DataOutputStream(s.getOutputStream()); bConnected = true; } catch (IOException e) { e.printStackTrace(); } } public void send(String str) { try { dos.writeUTF(str);// *这也是服务器发送给客户端的 } catch (SocketException e) { System.out.println("對方退出了");// } catch (IOException e) { e.printStackTrace(); } } // public void run() {// 核心(二) //实现接口,就必须重写接口里的方法 try { while (bConnected) { String str = dis.readUTF();// *是阻塞式的,没有发过来信息,就死死等着, for (int i = 0; i < clients.size(); i++) { ChatClient c = clients.get(i);// 服务器端获取多少个客户端与他连接,将信息发送给每一个客户端 c.send(str);// } } } catch (EOFException e) { System.out.println("客戶端退出了"); } catch (IOException e) { e.printStackTrace(); } finally { if (dis != null) if (s != null)// try {// dis.close(); s.close(); dos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }