【Java课程设计】仿QQ多人聊天室(基于TCP协议与JavaSwing)附下载

仿QQ多人聊天室

下载地址:链接:https://pan.baidu.com/s/1dLFjSxwTA4gL5lI0B4UGuQ 
提取码:2qs0

有两个项目,分别是服务器chatterServer和客户端chatter,先开启服务器,再开启客户端,默认8888端口。

先上图(回环测试,即自己和自己聊天):

实现的主要功能:

1、一对一聊天:连接到服务器的所有客户端和另一个客户端“一对一”聊天

2、多对多聊天:连接到服务器的所有客户端在同一聊天室内聊天

使用到的Java技术:

1、Java图形界面编程(JFrame和各种组件的使用)。还包括内部类,事件监听。

2、Java IO。主要是字节流,聊天信息通过字节流编码并发送、接收。

3、Java TCP通信。

4、Java多线程。

5、Java集合。其中一个重点是重写equals方法和hashCode方法

6、Java异常处理

代码结构:

客户端

代码分为4个包:

com.chatter.GUI 和图形界面相关的类,主要是GUI类
com.chatter.client 和客户端后台有关的类,主要是Client类
com.chatter.user 和用户信息存储有关的类,包含Message类(数据的打包和解包),User类(用户信息,最后没用),PersonRecord类(用于记录和某个特定客户端的聊天记录),Record类(用于记录用户和每个其他用户的聊天记录)
com.chatter.main main方法

项目类图(客户端):

服务器只有一个类,和从客户端复制过去的一些类

主要代码如下:

UI模块:

package com.chatter.gui;

import java.awt.*;
import java.awt.event.*;
import java.util.Collection;
import java.util.HashSet;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import com.chatter.client.Client;
import com.chatter.user.Message;
import com.chatter.user.PersonRecord;
import com.chatter.user.User;

public class GUI {
	Client client;
	
	JFrame frame;
	Container pane;
	JPanel window, up, left, center, down;
	
	//上方的软件名
	private JLabel label;
	//左侧选择聊天对象的列表
	JList<String> list;
	DefaultListModel<String> dlm;
	//中间的聊天消息显示
	JTextArea text;
	//下方输入文本的区域
	public JTextField words;
	//发送按钮
	JButton button;
	
	
	final int WINDOW_WIDTH = 480;
	final int WINDOW_HEIGHT = 640;
	
	final double CUT_RATE_LEFT = 0.30;
	
	
	public GUI() {
		frame = new JFrame();
	
		pane = frame.getContentPane();
		window = new JPanel(new BorderLayout());
		up = new UpperPanel();
		left = new JPanel();
		center = new JPanel();
		down = new JPanel(new BorderLayout());
		
		//上方的软件图标和名称
		label = new JLabel();
		label.setPreferredSize(new Dimension(150,50));
		label.setFont(new Font("楷体", Font.PLAIN, 30));
		label.setText("GG聊天室");
		up.add(label);
		pane.add(BorderLayout.NORTH, up);
		
		//左侧的聊天对象选择栏
		dlm = new DefaultListModel<String>();
		list = new JList<String>(dlm);
		list.setPreferredSize(new Dimension((int)(CUT_RATE_LEFT*WINDOW_WIDTH), 400));
		
		list.setModel(dlm);
		dlm.clear();
		dlm.addElement("0000000000008888");
		list.setSelectedIndex(0);
		list.addListSelectionListener((ListSelectionListener) new ListListener());;
		left.add(list);
		pane.add(BorderLayout.WEST, left);
		
		//中心的聊天消息显示
		text = new JTextArea();
		//text.setPreferredSize(new Dimension(280,2000));
		text.setEditable(true);
		text.setLineWrap(true);
		JScrollPane scrollpane1 = new JScrollPane(text);
		scrollpane1.setPreferredSize(new Dimension(300, 400));
		scrollpane1.createVerticalScrollBar().setVisible(false);
		scrollpane1.createHorizontalScrollBar().setVisible(true);
		center.add(scrollpane1);
		pane.add(BorderLayout.CENTER, center);
		
		//下方的聊天内容输入
		words = new JTextField();
		//words.setText("你好,我已经加你为好友\n,我们可以开始聊天了");
		words.setEditable(true);

		//words.setLineWrap(true);
		//words.setWrapStyleWord(true);
		JScrollPane scrollpane2= new JScrollPane(words);
		scrollpane2.setPreferredSize(new Dimension(350, 100));
		scrollpane2.createVerticalScrollBar().setVisible(false);
		scrollpane2.createHorizontalScrollBar().setVisible(true);
		//scrollpane2.setAutoscrolls(true);
		
		down.add(BorderLayout.WEST, scrollpane2);
		
		//发送按钮
		button = new JButton("发送");
		BottonListener bl = new BottonListener();
		//bl.setTextField(words);
		button.addActionListener(bl);
		button.setPreferredSize(new Dimension(100, 30));
		down.add(BorderLayout.EAST, button);
		
		pane.add(BorderLayout.SOUTH, down);
		
		frame.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
	
	public void receive(Message msg) {
		System.out.println("收到消息,准备更新. msg Type: " + msg.getHead());
		if (msg.getHead() == 1) {
			String[] s = msg.getContent().split("[|]");
			Collection<PersonRecord> tmp_c = new HashSet<PersonRecord>();
			for(String str:s) {
				tmp_c.add(new PersonRecord(Long.parseLong(str)));
				System.out.println(str);
			}
			tmp_c.add(new PersonRecord(8888));
			System.out.println("新建列表内容");
			for (Object o:tmp_c.toArray()) {
				System.out.println(((PersonRecord)o).personId);
			}
			System.out.println("_______ENC");
			client.record.c.addAll(tmp_c);
			client.record.c.retainAll(tmp_c);
			System.out.println("加入后原列表内容");
			for (Object o:client.record.c.toArray()) {
				System.out.println(((PersonRecord)o).personId);
			}
			System.out.println("_______ENC2");
			
			//System.out.println("系统原有集合:"+(PersonRecord[])(client.record.c.toArray()));

			//System.out.println("新创建集合:"+ (PersonRecord[])(tmp_c.toArray()));
			
			
			for(PersonRecord pr: client.record.c) {
				if (dlm.contains(String.format("%016d" ,pr.personId)) == false)
					dlm.addElement(String.format("%016d" ,pr.personId));
			}
		}
		else if (msg.getHead() == 0)
			for(PersonRecord pr:client.record.c) {
				if(pr.personId == msg.getTransmitter())
					pr.chatRecord.append("对方:");
					pr.chatRecord.append(msg.getContent());
					pr.chatRecord.append("\n");
					text.setText(pr.chatRecord.toString());
			}
		else if (msg.getHead() == 99) {
			for(PersonRecord pr:client.record.c) {
				pr.chatRecord.append("对方:");
				pr.chatRecord.append(msg.getContent());
				pr.chatRecord.append("\n");
				text.setText(pr.chatRecord.toString());
			}
		}
	}
	public void send(String content) {
		System.out.println("正在发送给"+list.getSelectedValue()+" 内容:" + content);
		Message m = new Message();
		content.replaceAll("\\n", "");
		m.setContent(content);
		
		//0:普通消息
		if (Long.parseLong(list.getSelectedValue()) == 8888) {
			m.setHead(99);
			m.setReceiver(Long.parseLong(list.getSelectedValue()));
		}
		else {
			m.setHead(0);
			m.setReceiver(Long.parseLong(list.getSelectedValue()));
		}
		System.out.println("发送与接收者:" +m.getTransmitter() +" "+m.getReceiver());
		for(PersonRecord pr:client.record.c) {
			System.out.println("现有用户id:"+pr.personId);
			if(pr.personId == m.getReceiver()) {
				System.out.println("正在添加聊天记录");
				pr.chatRecord.append("你:");
				pr.chatRecord.append(m.getContent());
				pr.chatRecord.append("\n");
				text.setText(pr.chatRecord.toString());
			}
		}
		System.out.println("-------ready to send msg--------");
		client.send(m);
	}
	
	class BottonListener implements ActionListener{
		public void actionPerformed(ActionEvent e) {
			String str = words.getText();
			if(str.trim().length() == 0) return;
			words.setText("");
			send(str);
		}	
	}
	class ListListener implements ListSelectionListener{

		public void actionPerformed(ActionEvent e) {
			
			
		}

		public void valueChanged(ListSelectionEvent e) {
			for(PersonRecord pr:client.record.c) {
				if(pr.personId == Long.parseLong(list.getSelectedValue()))
					text.setText(pr.chatRecord.toString());
			}
			
		}
		
	}
	
	public void setClient(Client c) {
		this.client = c;
	}
}

客户端后台Client:

package com.chatter.client;

import java.io.*;
import java.io.IOException;
import java.net.*;

import com.chatter.gui.GUI;
import com.chatter.user.Message;
import com.chatter.user.PersonRecord;
import com.chatter.user.Record;

public class Client {
	private String ip;
	private int port;
	private long localId;
	private Socket socket;
	private PrintWriter pw;
	private BufferedReader br;
	private GUI gui;
	public Record record;
	public Client(String ip, int port) {
		this.ip = ip;
		this.port = port;
		
		try {
			socket = new Socket(ip, port);
			OutputStream os = socket.getOutputStream();
			OutputStreamWriter osw = new OutputStreamWriter(os, "utf-8");
			BufferedWriter bw = new BufferedWriter(osw);
			pw = new PrintWriter(bw, true);
			
			InputStream is = socket.getInputStream();
			InputStreamReader isr = new InputStreamReader(is, "utf-8");
			br = new BufferedReader(isr);
			localId = getLocalId(ip, port); 
			
			record = new Record();
			//record.c.add(new PersonRecord(8888));
			
		}catch (Exception e) {
			System.out.println("连接服务器失败");
			System.exit(0);
		}
		
	}
	
	public boolean setGUI(GUI g) {
		if (g == null)
			return false;
		this.gui = g;
		return true;
	}
	
	
	public void start() {
		Thread t_receive = new Thread() {
			String line;
			public void run() {
				try {
					while((line = br.readLine()) != null) {
						try {
							System.out.print("收到新消息");
							System.out.println("\t" + line);
							Message msg = new Message(line);
							System.out.println("Before calling gui.receive: ");
							System.out.println(msg.getContent());
							gui.receive(msg);
						}catch(Exception e) {
							e.printStackTrace();
							System.out.println("Message encoding error");
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
					System.out.println("服务器主动断开连接。");
					System.exit(0);
				}
				
			}
		};
		t_receive.start();
	}
	static public long getLocalId(String IP, int port) {
		String[] ipSplit = IP.split("\\.");
		long[] arr = new long[5];
		for (int i=0; i<ipSplit.length; i++) {
			arr[i] = Integer.parseInt(ipSplit[i]);
		}
		arr[4] = port;
		return arr[4]+arr[3]*10000+arr[2]*10000000+arr[1]*1000000000L+arr[0]*10000000000000L;
	}
	
	
	public void send(Message msg) {
		if (msg.getHead() == 0) {
			System.out.println("Sending message to server...");
			msg.setTransmitter(localId);
			String str = msg.toString();
			System.out.println("\tmessage content: "+msg.getContent());
			pw.println(str);
		}
		else if (msg.getHead() == 99) {
			msg.setTransmitter(localId);
			
		}
	}
	
	public void setRecord(Record r) {
		this.record = r;
		record.c.add(new PersonRecord(8888));
	}
	
	
}


服务器Server:

package com.chatter.server;

import java.io.*;
import java.net.*;
import java.util.Collection;
import java.util.HashSet;

import com.chatter.user.Message;
import com.chatter.user.User;

public class Server {
	ServerSocket serverSocket;
	Collection<User> c = new HashSet<User>();
	
	public Server() {
		try {
			serverSocket = new ServerSocket(8888);
			
			while(true) {
				Socket socket = serverSocket.accept();
				long remoteID = getIDFromIP(socket.getInetAddress().getHostAddress());
				System.out.println(socket.getInetAddress() + "已连接");
				Thread thread = new Thread() {
					public void run() {
						try {
							OutputStream os = socket.getOutputStream();
							OutputStreamWriter osw = new OutputStreamWriter(os, "utf-8");
							BufferedWriter bw = new BufferedWriter(osw);
							PrintWriter pw = new PrintWriter(osw, true);
							
							InputStream is = socket.getInputStream();
							InputStreamReader isr = new InputStreamReader(is, "utf-8");
							BufferedReader br = new BufferedReader(isr);
							
							User u = new User(socket, getIDFromIP(socket.getInetAddress().getHostAddress()), br, pw);
						
							c.add(u);
							System.out.println(u.id + "已连接");
							sendUpdateMsg();
							//System.exit(0);
							
							String line;
							while((line = br.readLine()) != null) {
								Message msg = new Message(line);
								System.out.println("服务器收到消息: " + msg.toString());
								if (msg.getHead() == 0) {
									long id = msg.getReceiver();
									System.out.println("Receiver from raw msg: "+msg.getReceiver());
									//id = id*10000+8888;
									
									System.out.println("Sending to Client: "+id);
									for (User tmp: c) {
										System.out.println("服务器现有用户: "+tmp.id);
										if (tmp.id == id) {
											System.out.println("Sending to Client: "+tmp.socket.getInetAddress());
											tmp.pw.println(msg.toString());
											pw.flush();
										}
									}
								}
								else if (msg.getHead() == 99) {
									for (User tmp: c) {
										tmp.pw.println(msg.toString());
									}
								}
							} 
						}catch(Exception e) {
							for (User u: c) {
								if (u.id == remoteID) {
									c.remove(u);
									sendUpdateMsg();
								}
							}
							e.printStackTrace();;
						}
					}					
				};
				thread.start();
			}
			
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("服务器开启失败");
			System.exit(0);
		}
		
	}
	
	private void sendUpdateMsg() {
		System.out.println("发送在线列表更新信息中...");
		Message msg = new Message();
		msg.setHead(1);
		msg.setTransmitter(0);
		StringBuffer s = new StringBuffer();
		for (User tmp:c) {
			s.append(String.format("%016d", tmp.id));
			s.append('|');
		}
		msg.setContent(s.toString());
		for (User tmp:c) {
			System.out.println("Sending to "+tmp.id);
			msg.setReceiver(tmp.id);
			tmp.pw.println(msg.toString());
		}
	}
	private long getIDFromIP(String IP) {
		try {
			String[] ipSplit = IP.split("\\.");
			long[] arr = new long[5];
			for (int i=0; i<ipSplit.length; i++) {
				arr[i] = Integer.parseInt(ipSplit[i]);
			}
			arr[4] = 8888;
			return arr[4]+arr[3]*10000+arr[2]*10000000+arr[1]*1000000000L+arr[0]*10000000000000L;
			
		}catch(Exception e) {
			e.printStackTrace();
		}
		return 0;
	}
}

个人作品,请勿转载。

发布了86 篇原创文章 · 获赞 56 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/WilliamCode/article/details/104362321