下载地址:链接:https://pan.baidu.com/s/1dLFjSxwTA4gL5lI0B4UGuQ
提取码:2qs0
有两个项目,分别是服务器chatterServer和客户端chatter,先开启服务器,再开启客户端,默认8888端口。
先上图(回环测试,即自己和自己聊天):
1、一对一聊天:连接到服务器的所有客户端和另一个客户端“一对一”聊天
2、多对多聊天:连接到服务器的所有客户端在同一聊天室内聊天
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方法 |
服务器只有一个类,和从客户端复制过去的一些类
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 list;
DefaultListModel 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();
list = new JList(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 tmp_c = new HashSet();
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;
}
}
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
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 c = new HashSet();
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
个人作品,请勿转载。