客户端新建建socket与服务端建立连接,服务端每接收到一个连接都新建一个输入流和输出流,分别存储到对应的list列表里,使用多线程接收来自客户端的消息并处理,然后循环遍历所有连接广播消息。客户端则接收消息判断发送方和接收方,从而显示到对应的窗口。
//最大的是一个
JTabbedPane tabbedPane;//默认添加了一个群聊的JTextArea,私聊的时候根据list监听动态添加
//左侧用了一个JList,为了动态添加数据,给他设置了一个动态模型
JList list;//显示用户列表,根据服务器发送的用户更新
DefaultListModel listmodel;//列表模型
//底部就是一个标签+文本框+俩按钮
组件定义
JFrame frame;//窗口
JTextArea msg;//群聊对话框
JTextField text_str_send;//消息发送框
JButton sendBtn;//消息发送按钮
JButton exitBtn;//退出按钮
String user="";//用户名
Socket socket;//套接字
BufferedReader br;//输入流
BufferedWriter bw;//输出流
JTabbedPane tabbedPane;//对话列表
JList list;//显示用户列表
DefaultListModel listmodel;//列表模块
ArrayList<oneForone> oneForones=new ArrayList<oneForone>();//存储私聊对象
public static boolean user_is_alive=false;//判断用户是否还在
JScrollPane jsp=new JScrollPane(msg);//滚动条
tabbedPane = new JTabbedPane(JTabbedPane.TOP);
tabbedPane.setBounds(20, 35, 410, 368);
tabbedPane.add("群聊",jsp);
frame.getContentPane().add(tabbedPane);
listmodel = new DefaultListModel();//动态模型
list = new JList(listmodel);
list.setBounds(440, 60, 92, 340);
list.addMouseListener(new MouseAdapter() {//list的监听,当有双击事件就添加一个私聊窗口
public void mouseClicked(MouseEvent evt) {
if (evt.getClickCount() == 2) {//鼠标双击事件
String name=(String) list.getSelectedValue();//获取双击的名字
JTextArea msg=new JTextArea();
tabbedPane.add(name,msg);
oneForone oneforone=new oneForone(msg, name);
oneForones.add(oneforone);
}
}
});
当用户进入聊天室会调用方法public void setConnection(Socket socket)
用于创建套接字连接这时会向服务器发送上线的 消息,服务器将这个消息处理转发给全部用户
客户端:
public void setConnection(Socket socket) {
this.socket=socket;
try {
br=new BufferedReader(new
InputStreamReader(socket.getInputStream()));
bw=new BufferedWriter(new
OutputStreamWriter(socket.getOutputStream()));
user_is_alive=true;
// msg.append(another+"上线"+"\n");
bw.write("join:"+user+"\n");
bw.flush();
Thread thread=new Thread(this);
thread.start();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
服务器:
if(strMsg.indexOf("join")==0) {//有人加入聊天室
String user_=strMsg.split(":")[1];
chatserver.user.addFirst(user_);//增加用户列
String User="USER";
for(int i=0;i<chatserver.user.size();i++)
User+=(":"+chatserver.user.get(i));
chatserver.msgList.add(User);
strMsg="系统通知-"+strMsg.split(":")[1]+"-加入聊天室\n";
System.out.println(user_+"join");
}
用户会调用shutdown方法void shutdown()
依旧会向服务器发送退出的消息,服务器处理后转发,然后用户关闭进程
用户:
//退出
void shutdown() {
user_is_alive=false;
try {
bw.write("exit:"+user);
bw.flush();
bw.close();
socket.close();
this.dispose();
System.exit(0);
}catch (Exception e) {
// TODO: handle exception
}
}
服务器:
if(strMsg.indexOf("exit")==0) {//有人退出聊天室
chatserver.ins.remove(in);
chatserver.outs.remove(out);
String user_=strMsg.split(":")[1];
//删除用户列
for(int i=0;i<chatserver.user.size();i++)
if(chatserver.user.get(i).equals(user_))
chatserver.user.remove(i);
String User="USER";
for(int i=0;i<chatserver.user.size();i++)
User+=(":"+chatserver.user.get(i));
chatserver.msgList.add(User);
strMsg="系统通知-"+strMsg.split(":")[1]+"-退出聊天室\n";
System.out.println(user_+"exit");
chatserver.msgList.addFirst(strMsg);
break;
}
当有用户进入聊天室和退出聊天室时右侧用户列表会跟新
服务器:
新建一个用户列表
当服务器接收到来自用户的上线请求时,添加到列表里,然后向客户端传输所有用户信息,格式USER:user1:user2:user3...
public static LinkedList<String> user=new LinkedList<String>();//当前在线用户列表
if(strMsg.indexOf("join")==0) {//有人加入聊天室
String user_=strMsg.split(":")[1];
chatserver.user.addFirst(user_);//增加用户列
String User="USER";
for(int i=0;i<chatserver.user.size();i++)
User+=(":"+chatserver.user.get(i));
chatserver.msgList.add(User);//向转发列表添加这条消息
用户端:
当接收到USER:
开头的消息时根据消息体跟新在线用户
content_recv=br.readLine();//获取消息体
//有人加入或者退出聊天室更新在线成员
if(content_recv.indexOf("USER")==0) {
String msString[]=content_recv.split(":");
listmodel.removeAllElements();
for(int i=1;i<msString.length;i++) {
listmodel.addElement(msString[i]);//使用list的动态模型更新
}
}
消息格式:from|values|to
from为发送方,values为消息体,to是接收方,群聊的to默认为“群聊”
方法:获取当前标签页的标题,确定接收方,然后增加自身姓名和发送的消息为一个完整的消息体,然后发送
//发送消息
void sendmessage() {
try {
String to = tabbedPane.getTitleAt(tabbedPane.getSelectedIndex());//获取当前页
String value=text_str_send.getText();
String send_msg=user+"|"+value+"|"+to+"\n";
// String content_send=user+":"+text_str_send.getText()+"\n";//消息体
//当不是群聊时,在当前页显示自己发送的消息
if(!to.equals("群聊")) {
for(int i=0;i<oneForones.size();i++)
if(oneForones.get(i).getName().equals(to)) {
oneForones.get(i).getMsg().append(user+":"+value+"\n");
}
}
bw.write(send_msg);
bw.flush();
// msg.append(content_send);
text_str_send.setText("");
}catch (Exception e) {
// TODO: handle exception
}
}
将消息按照|分割,确定消息类型,群聊则显示在群聊JTextarea里私聊则在私聊对象的列表里寻找
私聊对象
class oneForone extends JFrame{
JTextArea msg;//私聊对象的对话框
String name;//私聊对象姓名
public oneForone(JTextArea msg,String name) {
this.name=name;
this.msg=msg;
}
public JTextArea getMsg() {
return msg;
}
public String getName() {
return name;
}
}
处理消息体
content_recv=br.readLine();
//有人加入或者退出聊天室更新在线成员
if(content_recv.indexOf("USER")==0) {
String msString[]=content_recv.split(":");
listmodel.removeAllElements();
for(int i=1;i<msString.length;i++) {
listmodel.addElement(msString[i]);
}
}else {
if(content_recv.indexOf("系统通知")==0) {
msg.append(content_recv+"\n");
}else {
String Temp[]=content_recv.split("\\|");//使用|作为分隔符要用\\转义
if(Temp.length==3) {
if(Temp[2].equals("群聊"))
msg.append(Temp[0]+":"+Temp[1]+"\n");
else if(Temp[2].equals(user)){//私聊
boolean flag=false;
for(int i=0;i<oneForones.size();i++) {
if(oneForones.get(i).getName().equals(Temp[0])) {
oneForones.get(i).getMsg().append(Temp[0]+":"+Temp[1]+"\n");
flag=true;
break;
}
}
if(!flag) {//没有打开私聊窗口则打开
JTextArea msg=new JTextArea();
tabbedPane.add(Temp[0],msg);
oneForone oneforone=new oneForone(msg, Temp[0]);
oneForones.add(oneforone);
msg.append(Temp[0]+":"+Temp[1]+"\n");
}
System.out.print(Temp[0]+":"+Temp[1]+"\n");
}
}
}
}
完整代码:
chatclient.java
public class chatclient extends JFrame{
private JTextField id;
private JTextField pasword;
private JFrame frame;
public chatclient() {
frame=new JFrame("用户登录");
frame.getContentPane().setLayout(null);
JLabel lblNewLabel = new JLabel("姓名:");
lblNewLabel.setBounds(50, 41, 99, 23);
frame.getContentPane().add(lblNewLabel);
id = new JTextField();
id.setBounds(131, 42, 179, 21);
frame.getContentPane().add(id);
id.setColumns(10);
JLabel lblNewLabel_1 = new JLabel("密码:");
lblNewLabel_1.setBounds(50, 91, 99, 23);
frame.getContentPane().add(lblNewLabel_1);
pasword = new JTextField();
pasword.setBounds(131, 92, 179, 21);
frame.getContentPane().add(pasword);
pasword.setColumns(10);
JButton btnNewButton = new JButton("登录");
btnNewButton.setBackground(Color.WHITE);
btnNewButton.setBounds(152, 168, 93, 23);
btnNewButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
String name=id.getText();
try {
Socket socket=new Socket("localhost",8888);
chatting_interface_multi clInterface_multi=new chatting_interface_multi(name);
clInterface_multi.setConnection(socket);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
frame.dispose();
}
});
frame.getContentPane().add(btnNewButton);
frame.setVisible(true);
frame.setSize(410,298);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
new chatclient();
}
}
chatserver.java
package 聊天室2_多人聊天室;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;
public class chatserver {
public static ArrayList<BufferedReader> ins=new ArrayList<BufferedReader>();
public static ArrayList<BufferedWriter> outs=new ArrayList<BufferedWriter>();
public static LinkedList<String> msgList=new LinkedList<String>();
public static LinkedList<String> user=new LinkedList<String>();//当前在线用户列表
public static Thread t_send,t_accept;
public static ServerSocket serverSocket;
public chatserver() {
try {
serverSocket=new ServerSocket(8888);
AcceptSocket as=new AcceptSocket();
SendSocket ss=new SendSocket();
// Socket socket=serverSocket.accept();
// chatting_interface_multi srvif=new
// chatting_interface_multi("服务器端");
// srvif.setConnection(socket);
t_accept=new Thread(as);
t_accept.start();
t_send=new Thread(ss);
t_send.start();
System.out.println("服务器启动...........");
System.out.println("启动完成");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[]args) {
new chatserver();
}
}
class AcceptSocket implements Runnable{
public void run() {
while(chatserver.t_accept.isAlive()) {
try {
Socket socket=chatserver.serverSocket.accept();
if(socket!=null) {
BufferedReader in=new
BufferedReader(new InputStreamReader(socket.getInputStream()));
chatserver.ins.add(in);
BufferedWriter out=new
BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
chatserver.outs.add(out);
new GetMsgFromClient(in,out).start();
}
}catch(Exception e) {
}
}
}
}
class GetMsgFromClient extends Thread{
BufferedReader in;BufferedWriter out;
public GetMsgFromClient(BufferedReader in,BufferedWriter out) {
this.in=in;this.out=out;
}
public void run() {
while(this.isAlive()) {
try {
String strMsg=in.readLine();
if(strMsg!=null) {
if(strMsg.indexOf("exit")==0) {//有人退出聊天室
chatserver.ins.remove(in);
chatserver.outs.remove(out);
String user_=strMsg.split(":")[1];
//删除用户列
for(int i=0;i<chatserver.user.size();i++)
if(chatserver.user.get(i).equals(user_))
chatserver.user.remove(i);
String User="USER";
for(int i=0;i<chatserver.user.size();i++)
User+=(":"+chatserver.user.get(i));
chatserver.msgList.add(User);
strMsg="系统通知-"+strMsg.split(":")[1]+"-退出聊天室\n";
System.out.println(user_+"exit");
chatserver.msgList.addFirst(strMsg);
break;
}
if(strMsg.indexOf("join")==0) {//有人加入聊天室
String user_=strMsg.split(":")[1];
chatserver.user.addFirst(user_);//增加用户列
String User="USER";
for(int i=0;i<chatserver.user.size();i++)
User+=(":"+chatserver.user.get(i));
chatserver.msgList.add(User);
strMsg="系统通知-"+strMsg.split(":")[1]+"-加入聊天室\n";
System.out.println(user_+"join");
}
chatserver.msgList.addFirst(strMsg);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
break;
}
}
}
}
class SendSocket implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
while(chatserver.t_send.isAlive()) {
try {
if(!chatserver.msgList.isEmpty()) {
String string=chatserver.msgList.removeLast();
for(int i=0;i<chatserver.outs.size();i++) {
chatserver.outs.get(i).write(string+"\n");
chatserver.outs.get(i).flush();
// System.out.println(chatserver.outs.get(i).toString());
}
}
}catch (Exception e) {
// TODO: handle exception
}
}
}
}
chatting_interface_multi.java
package 聊天室2_多人聊天室;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.FontFormatException;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.EmptyBorder;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.awt.event.ActionEvent;
import javax.swing.JTabbedPane;
import javax.swing.JList;
public class chatting_interface_multi extends JFrame implements ActionListener,Runnable{
JFrame frame;//窗口
JTextArea msg;//群聊对话框
JTextField text_str_send;//消息发送框
JButton sendBtn;//消息发送按钮
JButton exitBtn;//退出按钮
String user="";//用户名
Socket socket;//套接字
BufferedReader br;//输入流
BufferedWriter bw;//输出流
JTabbedPane tabbedPane;//对话列表
JList list;//显示用户列表
DefaultListModel listmodel;//列表模块
ArrayList<oneForone> oneForones=new ArrayList<oneForone>();//存储私聊对象
public static boolean user_is_alive=false;//判断用户是否还在
public chatting_interface_multi(String user) {
this.user=user;
frame=new JFrame("用户:"+user);
frame.getContentPane().setLayout(null);
msg = new JTextArea();
JLabel label = new JLabel("输入消息");
label.setBounds(20, 413, 85, 15);
frame.getContentPane().add(label);
text_str_send = new JTextField();
text_str_send.setBounds(78, 413, 297, 21);
frame.getContentPane().add(text_str_send);
text_str_send.setColumns(10);
text_str_send.addActionListener(this);
sendBtn = new JButton("发送");
sendBtn.setBounds(385, 412, 70, 23);
frame.getContentPane().add(sendBtn);
sendBtn.addActionListener(this);
exitBtn = new JButton("退出");
exitBtn.setBounds(465, 413, 65, 23);
frame.getContentPane().add(exitBtn);
JScrollPane jsp=new JScrollPane(msg);//滚动条
tabbedPane = new JTabbedPane(JTabbedPane.TOP);
tabbedPane.setBounds(20, 35, 410, 368);
tabbedPane.add("群聊",jsp);
frame.getContentPane().add(tabbedPane);
listmodel = new DefaultListModel();
list = new JList(listmodel);
list.setBounds(440, 60, 92, 340);
list.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt) {
if (evt.getClickCount() == 2) {//鼠标双击事件
String name=(String) list.getSelectedValue();//获取双击的名字
JTextArea msg=new JTextArea();
tabbedPane.add(name,msg);
oneForone oneforone=new oneForone(msg, name);
oneForones.add(oneforone);
}
}
});
frame.getContentPane().add(list);
exitBtn.addActionListener(this);
frame.setVisible(true);
frame.setSize(558,487);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void setConnection(Socket socket) {
this.socket=socket;
try {
br=new BufferedReader(new
InputStreamReader(socket.getInputStream()));
bw=new BufferedWriter(new
OutputStreamWriter(socket.getOutputStream()));
user_is_alive=true;
// msg.append(another+"上线"+"\n");
bw.write("join:"+user+"\n");
bw.flush();
Thread thread=new Thread(this);
thread.start();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
String content_recv;
while(user_is_alive) {
content_recv=br.readLine();
//有人加入或者退出聊天室更新在线成员
if(content_recv.indexOf("USER")==0) {
String msString[]=content_recv.split(":");
listmodel.removeAllElements();
for(int i=1;i<msString.length;i++) {
listmodel.addElement(msString[i]);
}
}else {
if(content_recv.indexOf("系统通知")==0) {
msg.append(content_recv+"\n");
}else {
String Temp[]=content_recv.split("\\|");//使用|作为分隔符要用\\转义
if(Temp.length==3) {
if(Temp[2].equals("群聊"))
msg.append(Temp[0]+":"+Temp[1]+"\n");
else if(Temp[2].equals(user)){//私聊
boolean flag=false;
for(int i=0;i<oneForones.size();i++) {
if(oneForones.get(i).getName().equals(Temp[0])) {
oneForones.get(i).getMsg().append(Temp[0]+":"+Temp[1]+"\n");
flag=true;
break;
}
}
if(!flag) {//没有打开私聊窗口则打开
JTextArea msg=new JTextArea();
tabbedPane.add(Temp[0],msg);
oneForone oneforone=new oneForone(msg, Temp[0]);
oneForones.add(oneforone);
msg.append(Temp[0]+":"+Temp[1]+"\n");
}
System.out.print(Temp[0]+":"+Temp[1]+"\n");
}
}
}
}
}
}catch(Exception e) {
// e.printStackTrace();
return;
}
}
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(e.getSource()==sendBtn||e.getSource()==text_str_send) {
//发送消息
sendmessage();
}else if(e.getSource()==exitBtn) {
//退出
shutdown();
}
}
//发送消息
void sendmessage() {
try {
String to = tabbedPane.getTitleAt(tabbedPane.getSelectedIndex());//获取当前页
String value=text_str_send.getText();
String send_msg=user+"|"+value+"|"+to+"\n";
// String content_send=user+":"+text_str_send.getText()+"\n";//消息体
if(!to.equals("群聊")) {
for(int i=0;i<oneForones.size();i++)
if(oneForones.get(i).getName().equals(to)) {
oneForones.get(i).getMsg().append(user+":"+value+"\n");
}
}
bw.write(send_msg);
bw.flush();
// msg.append(content_send);
text_str_send.setText("");
}catch (Exception e) {
// TODO: handle exception
}
}
//退出
void shutdown() {
user_is_alive=false;
try {
bw.write("exit:"+user);
bw.flush();
bw.close();
socket.close();
this.dispose();
System.exit(0);
}catch (Exception e) {
// TODO: handle exception
}
}
}
class oneForone extends JFrame{
JTextArea msg;
String name;
public oneForone(JTextArea msg,String name) {
this.name=name;
this.msg=msg;
}
public JTextArea getMsg() {
return msg;
}
public String getName() {
return name;
}
}