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 + "
");
		fieldMsg.setText("");
		try {
			Date d = new Date();
			out.writeUTF("
" + msg + "
" + 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 + "
");// 我曾修改过
				} 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();
						}
			}
		}
	}
}

  

原文地址:https://www.cnblogs.com/langlove/p/3484622.html