java网络程序设计 聊天室之私聊、群聊和清屏功能的实现

TCP聊天室实现了私聊、群聊和清屏的功能,简陋的UI界面,一个服务器端,支持多个客户端之间的通信。

系统功能简介:

1.客户端登录成功后可以查看聊天室用户列表,并可以进行个人聊天和群聊。

2.服务器启动后绑定端口侦听客户端连接,并为每个客户端创建一个处理线程。服务器维护一个包括有用户和客户端套接字的用户列表。

3.所有的聊天消息都通过服务器转发完成,服务器将接收客户端聊天消息转发到指定目的地。客户端只获知其他用户的用户名,无法知道其网络信息。

4.显示聊天室在线的人数。

技术要点说明:
(1)聊天室LOGIN、LOGOUT、USERLIST、TALKTO、TALKTO_ALL等报文类型。程序中使用DataOutputStream中writeUTF()方法完成消息报文的读写。不使用BufferedReader中read Line()的原因是该方法只能读取一行文本,如何消息是包括有换行符的多行文本,则无法识别。
(2)将信息报文的发送、接受封装在Utils工具类中。
(3)使用JList控件显示客户端的用户列表。控件的数据保存在DefaultListModel数据模型对象中。

(4)由于聊天室的用户名不能相同,服务器端使用HashMap<String,Socket>存放每个用户和客户端套接字的映射。

下面附上完整代码

Utils工具类:

package wechat;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.JTextArea;
import javax.xml.crypto.Data;
import org.omg.CORBA.Any;
import org.omg.CORBA.DataInputStream;
//将消息报文的发送、接受封装在Utils工具类中
public class Utils {
//通过套接字S发送字符串
public static void sendMsg(Socket s,String msg){
try{
//字符流
DataOutputStream dos =new DataOutputStream(s.getOutputStream());
dos.writeUTF(msg);
dos.flush();
}catch(IOException e){
e.printStackTrace();
}
}

//在套接字S上读取字符串,如果TCP连接关闭,返回null
public static String recvMsg(Socket s) throws IOException{
String msg=null;
DataInputStream dis=(DataInputStream) new java.io.DataInputStream(s.getInputStream());
msg=((java.io.DataInputStream) dis).readUTF();
return msg;

}
//获取格式化的当前时间字符串形式
public static String getTimeStr(){
SimpleDateFormat fm=new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");

return fm.format(new Date());

}
//添加消息到文本记录框JTextArea ,并且滚动显示到最后一行
public static void addMsgRec(JTextArea textArea,String msg){
textArea.append(msg+"\n");
textArea.setCaretPosition(textArea.getText().length());
}
}


服务端: 

package wechat;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.HashMap;
import javax.swing.AbstractButton;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
public class ChatServer {
// 添加用于功能实现的成员变量
/**
* 服务器套接字
*/
private ServerSocket server;

/**
* 判断服务器是否在运行
*/
private boolean isRunning;

/**
* 客户端映射,key -> String:客户端名称; value -> ClientHandler: 客户端处理线程
*/
//用户名不能相同,使用HashMap<String, ClientHandler>存放每个用户和客户端套接字的映射。
private HashMap<String, ClientHandler> clientHandlerMap = new HashMap<String, ClientHandler>();
private JFrame frmTcp;
private JTextField textServerIP;//ip 
private JTextField textPort;//端口
private JTable tblUsers;//在线用户列表
private JButton btnStart;//启动
private JButton btnStop;//停止
private JTextArea textAreaRecord;//文本记录框

/**
* Launch the application.
*/
//主函数
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ChatServer window = new ChatServer();
window.frmTcp.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}


/**
* Create the application.
*/
public ChatServer() {
initialize();
}


/**
* Initialize the contents of the frame.
*/
//服务器界面
private void initialize() {
frmTcp = new JFrame();
frmTcp.setResizable(false);
frmTcp.setTitle("TCP\u804A\u5929\u5BA4\u670D\u52A1\u5668");
frmTcp.setBounds(100, 100, 700, 509);
frmTcp.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmTcp.getContentPane().setLayout(null);

//IP框
JLabel lblip = new JLabel("\u670D\u52A1\u5668IP\u5730\u5740:");
lblip.setBounds(10, 27, 105, 18);
frmTcp.getContentPane().add(lblip);
textServerIP = new JTextField();
textServerIP.setText("0.0.0.0");
textServerIP.setBounds(114, 24, 141, 24);
frmTcp.getContentPane().add(textServerIP);
textServerIP.setColumns(10);
//端口框
JLabel label = new JLabel("\u7AEF\u53E3\u53F7:");
label.setBounds(293, 27, 72, 18);
frmTcp.getContentPane().add(label);
textPort = new JTextField();
textPort.setText("8000");
textPort.setBounds(356, 24, 86, 24);
frmTcp.getContentPane().add(textPort);
textPort.setColumns(10);
//开始按钮
btnStart = new JButton("\u542F\u52A8");
btnStart.setBounds(479, 23, 95, 27);
frmTcp.getContentPane().add(btnStart);
// 启动按钮事件监听处理
btnStart.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
// 创建、启动服务器通信线程
Thread serverThread = new Thread(new ServerThread());
serverThread.start();
}
});
//停止按钮
btnStop = new JButton("\u505C\u6B62");
btnStop.setEnabled(false);
btnStop.setBounds(588, 23, 95, 27);
frmTcp.getContentPane().add(btnStop);
// 停止按钮事件监听处理
btnStop.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
try {
isRunning = false;
// 关闭服务器套接字,清空客户端映射
server.close();
clientHandlerMap.clear();

// 修改按钮状态
btnStart.setEnabled(true);
btnStop.setEnabled(false);
addMsg("服务器关闭成功");
} catch (IOException e) {
e.printStackTrace();
}
}
});


JLabel label_1 = new JLabel("\u6D88\u606F\u8BB0\u5F55");
label_1.setBounds(10, 58, 72, 18);
frmTcp.getContentPane().add(label_1);


JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(10, 78, 673, 159);
frmTcp.getContentPane().add(scrollPane);

textAreaRecord = new JTextArea();
textAreaRecord.setEditable(false);
scrollPane.setViewportView(textAreaRecord);


JLabel lblNewLabel = new JLabel("\u5728\u7EBF\u7528\u6237\u5217\u8868");
lblNewLabel.setBounds(10, 250, 105, 18);
frmTcp.getContentPane().add(lblNewLabel);


JScrollPane scrollPane_1 = new JScrollPane();
scrollPane_1.setBounds(10, 273, 673, 191);
frmTcp.getContentPane().add(scrollPane_1);

//在线用户列表
tblUsers = new JTable();
tblUsers.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
tblUsers.setModel(new DefaultTableModel(new Object[][] {},
new String[] { "\u5E8F\u53F7", "\u7528\u6237\u540D",
"IP\u5730\u5740", "\u7AEF\u53E3\u53F7",
"\u767B\u5F55\u65F6\u95F4" }) {
boolean[] columnEditables = new boolean[] { true, true, true,
false, true };


public boolean isCellEditable(int row, int column) {
return columnEditables[column];
}
});
tblUsers.getColumnModel().getColumn(0).setPreferredWidth(56);
tblUsers.getColumnModel().getColumn(1).setPreferredWidth(118);
tblUsers.getColumnModel().getColumn(2).setPreferredWidth(126);
tblUsers.getColumnModel().getColumn(3).setResizable(false);
tblUsers.getColumnModel().getColumn(3).setPreferredWidth(61);
tblUsers.getColumnModel().getColumn(4).setPreferredWidth(122);
scrollPane_1.setViewportView(tblUsers);
// 更换样式
try {
String style = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
UIManager.setLookAndFeel(style);
// 更新窗体样式
SwingUtilities.updateComponentTreeUI(this.frmTcp);
} catch (Exception e) {
e.printStackTrace();
}
}

//内部类,服务器后台线程
class ServerThread implements Runnable {

/**
* 启动服务
*/
private void startServer() {
try {
// 获取serverIp 和 serverPort
String serverIp = textServerIP.getText();
int serverPort = Integer.parseInt(textPort.getText());
// 创建套接字地址
SocketAddress socketAddress = new InetSocketAddress(serverIp, serverPort);
// 创建ServerSocket,绑定套接字地址
server = new ServerSocket();
server.bind(socketAddress);
// 修改判断服务器是否运行的标识变量
isRunning = true;
// 修改启动和停止按钮状态
btnStart.setEnabled(false);
btnStop.setEnabled(true);
addMsg("服务器启动成功");

} catch (IOException e) {
addMsg("服务器启动失败,请检查端口是否被占用");
e.printStackTrace();
isRunning = false;
}
}
/*
public static final HashMap<String, ClientHandler> userList = null;
public static final ServerSocket s = null;
    public static final AbstractButton modelUsers = null;
//更新服务器用户列表的表格控件
public void updateUserTbl(){
//获取JTable的数据类型 private DefaultListModel<String> modelUsers
DefaultTableModel tblModel=(DefaultTableModel) modelUsers.getModel();
//清空原有的数据
while(tblModel.getRowCount()>0){
tblModel.removeRow(tblModel.getRowCount()-1);

}
int seq=1;
//重新添加数据
for(String textUsername : userList.keySet()){
   // Socket s=userList.get(textUsername);
    //获取远程IP地址和端口号。
   String remoteIP =s.getInetAddress().getHostAddress();
   String remotePort=String.valueOf(s.getLocalPort());
   String[] newRow={String.valueOf(seq),textUsername, remoteIP,remotePort,Utils.getTimeStr()};
   //添加新的一行记录
   tblModel.addRow(newRow);
   seq++;

}
}
*/

/**
* 线程主体
*/
@Override
public void run() {
startServer();
// 当服务器处于运行状态时,循环监听客户端的连接请求
while(isRunning) {
try {
Socket socket = server.accept();
// 创建与客户端交互的线程
Thread thread = new Thread(new ClientHandler(socket));
thread.start();
} catch (IOException e) {


}
}
}

}

//内部类,用于和客户端交互
class ClientHandler implements Runnable {
private Socket socket;
private DataInputStream dis;
private DataOutputStream dos;
private boolean isConnected;
private String username;

public ClientHandler(Socket socket) {
this.socket = socket;
try {
this.dis = new DataInputStream(socket.getInputStream());
this.dos = new DataOutputStream(socket.getOutputStream());
isConnected = true;
} catch (IOException e) {
isConnected = false;
e.printStackTrace();
}
}


public Object getInetAddress() {
// TODO Auto-generated method stub
return null;
}


@Override
public void run() {
while(isRunning && isConnected) {
try {
// 读取客户端发送的报文
String msg =dis.readUTF();
String[] parts = msg.split("#");
switch (parts[0]) {
// 处理登录报文
case "LOGIN":
String loginUsername = parts[1];
// 如果该用户名已登录,则返回失败报文,否则返回成功报文
if(clientHandlerMap.containsKey(loginUsername)) {
dos.writeUTF("FAIL");
} else {
dos.writeUTF("SUCCESS");
// 将此客户端处理线程的信息添加到clientHandlerMap中
clientHandlerMap.put(loginUsername, this);
// 将现有用户的信息发给新用户
StringBuffer msgUserList = new StringBuffer();
msgUserList.append("USERLIST#");
for(String username : clientHandlerMap.keySet()) {
msgUserList.append(username + "#");
}
dos.writeUTF(msgUserList.toString());
// 将新登录的用户信息广播给其他用户
String msgLogin = "LOGIN#" + loginUsername;

broadcastMsg(loginUsername, msgLogin);
//updateUserTbl();
// 存储登录的用户名
this.username = loginUsername;
updateUserTbl();
}
break;
//处理退出报文
case "LOGOUT":
clientHandlerMap.remove(username);
String msgLogout="LOGOUT#"+username;
broadcastMsg(username, msgLogout);
broadcastMsg(username,"LOGOUT#"+username);
isConnected=false;
socket.close();
updateUserTbl();
break;
case "TALKTO_ALL":
String msgTalkToAll="TALKTO_ALL#"+username+"#"+parts[1];
broadcastMsg(username, msgTalkToAll);

break;
case "TALKTO":
ClientHandler clientHandler=clientHandlerMap.get(parts[1]);
if(null!=clientHandler){
String msgTalkTo="TALKTO#"+username+"#"+parts[2];
clientHandler.dos.writeUTF(msgTalkTo);
clientHandler.dos.flush();
}


default:
break;
}
} catch (IOException e) {
isConnected = false;
e.printStackTrace();
}
}
}

/**
* 将某个用户发来的消息广播给其它用户
* @param fromUsername 发来消息的用户
* @param msg 需要广播的消息
*/
private void broadcastMsg(String fromUsername, String msg) throws IOException{
for(String toUserName : clientHandlerMap.keySet()) {
if(fromUsername.equals(toUserName) == false) {
DataOutputStream dos = clientHandlerMap.get(toUserName).dos;
dos.writeUTF(msg);
dos.flush();
}
}
}
}

/**
* 添加消息到文本框textAreaRecord
* @param msg,要添加的消息
*/
private void addMsg(String msg) {
// 在文本区中添加一条消息,并加上换行
textAreaRecord.append(msg + "\n");
// 自动滚动到文本区的最后一行
textAreaRecord.setCaretPosition(textAreaRecord.getText().length());
}


public void updateUserTbl() {
// TODO Auto-generated method stub

}


public Object getInetAddress() {
// TODO Auto-generated method stub
return null;
}


}


客户端: 

package wechat;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.ButtonGroup;
import javax.swing.DefaultListModel;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
public class ChatClient {

//public static final String msgLogout = null;


public static final String username = null;


//public static final String[] self = null;


//public static final String userList = null;


// 定义成员变量
/**
* 客户端通信线程
*/
private ClientThread clientThread;
private JFrame frmtcp;

private JTextField textServerIP;//IP
private JTextField textServerPort;//端口
private JTextArea textAreaRecord;//消息文本记录框
private JButton btnSend;//发送按钮
private JButton btnConnect;//登录按钮
private JButton btnpicture;//图片按钮
private JButton btnclear;//清屏按钮
private JTextField textUsername;//用户名
private JList<String> listUsers;//用户列表  Jlist控件显示客户端的用户列表。数据保存在DefaultListmodel数据模型对象中。
private JLabel lblRoomInfo;
private final ButtonGroup buttonGroup = new ButtonGroup();
private JRadioButton rdbtnBrocast;//群聊
private JRadioButton rdbtnPrivateChat;//私聊
private JTextArea textAreaMsg;//消息框
private DefaultListModel<String> modelUsers;//数据模型,用于更新数据
/**
* Launch the application.
*/
//主函数
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ChatClient window = new ChatClient();
window.frmtcp.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}


/**
* Create the application.
*/
public ChatClient() {
initialize();
modelUsers=new DefaultListModel();
// 初始化成员变量和随机用户名
modelUsers = new DefaultListModel<String>();
listUsers.setModel(modelUsers);
// 随机生成用户名
Random rand = new Random();
textUsername.setText("用户" + rand.nextInt(100));//随机生成0-99的用户

}
         


/**
* Initialize the contents of the frame.
*/

//客户端界面
private void initialize() {
frmtcp = new JFrame();
frmtcp.setResizable(false);
frmtcp.setTitle("TCP\u804A\u5929\u5BA4\u5BA2\u6237\u7AEF");
frmtcp.setBounds(100, 100, 715, 476);
frmtcp.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmtcp.getContentPane().setLayout(null);

JLabel lblNewLabel = new JLabel("\u670D\u52A1\u5668IP\u5730\u5740:");
lblNewLabel.setBounds(14, 24, 121, 18);
frmtcp.getContentPane().add(lblNewLabel);
//IP文本框
textServerIP = new JTextField();
textServerIP.setText("127.0.0.1");
textServerIP.setBounds(121, 21, 121, 24);
frmtcp.getContentPane().add(textServerIP);
textServerIP.setColumns(10);

JLabel lblNewLabel_1 = new JLabel("\u7AEF\u53E3\u53F7:");
lblNewLabel_1.setBounds(256, 24, 58, 18);
frmtcp.getContentPane().add(lblNewLabel_1);

//端口文本框
textServerPort = new JTextField();
textServerPort.setText("8000");
textServerPort.setBounds(313, 21, 48, 24);
frmtcp.getContentPane().add(textServerPort);
textServerPort.setColumns(10);

//登录按钮
btnConnect = new JButton("\u767B\u5F55");
btnConnect.setBounds(596, 20, 95, 27);
frmtcp.getContentPane().add(btnConnect);
// 连接按钮事件处理程序
btnConnect.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
// 判断当前登录状态
if (btnConnect.getText().equals("登录")) {
// 创建客户端通信线程
clientThread = new ClientThread();
clientThread.start();
} else {
clientThread.logout();
}

}
});


//清屏按钮
btnclear = new JButton("\u6E05\u5C4F");
btnclear.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
textAreaRecord.setText(""); 
}
});
btnclear.setBounds(474, 306, 58, 23);
frmtcp.getContentPane().add(btnclear);

//图片
btnpicture =new JButton("\u56FE\u7247");
btnpicture.setBounds(324, 306, 58, 23);
frmtcp.getContentPane().add(btnpicture);
// 连接按钮事件处理程序
btnpicture.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
//没实现
}
});

JLabel lblNewLabel_2 = new JLabel("\u6D88\u606F:");
lblNewLabel_2.setBounds(14, 313, 72, 18);
frmtcp.getContentPane().add(lblNewLabel_2);

//发送按钮
btnSend = new JButton("\u53D1\u9001");
btnSend.setEnabled(false);
btnSend.setBounds(444, 409, 88, 27);
frmtcp.getContentPane().add(btnSend);
// 连接按钮事件处理程序
btnSend.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent arg0) {
if(null!=clientThread){
clientThread.sendChatMsg();//ClientThread中的sendChatMsg方法,发送消息
}
}
});


JLabel label = new JLabel("\u6D88\u606F\u8BB0\u5F55");
label.setBounds(14, 55, 72, 18);
frmtcp.getContentPane().add(label);

JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(14, 72, 518, 228);
frmtcp.getContentPane().add(scrollPane);

//聊天记录框
textAreaRecord = new JTextArea();
textAreaRecord.setEditable(false);
scrollPane.setViewportView(textAreaRecord);

JLabel label_1 = new JLabel("\u7528\u6237\u540D:");
label_1.setBounds(375, 24, 58, 18);
frmtcp.getContentPane().add(label_1);
        
//用户名框
textUsername = new JTextField();
textUsername.setBounds(433, 21, 95, 24);
frmtcp.getContentPane().add(textUsername);
textUsername.setColumns(10);

JScrollPane scrollPane_1 = new JScrollPane();
scrollPane_1.setBounds(14, 332, 518, 73);
frmtcp.getContentPane().add(scrollPane_1);

//消息输入框
textAreaMsg = new JTextArea();
scrollPane_1.setViewportView(textAreaMsg);

JLabel label_2 = new JLabel("\u5728\u7EBF\u7528\u6237");
label_2.setBounds(543, 55, 72, 18);
frmtcp.getContentPane().add(label_2);


JScrollPane scrollPane_2 = new JScrollPane();
scrollPane_2.setBounds(546, 72, 149, 334);
frmtcp.getContentPane().add(scrollPane_2);

//用户列表框
listUsers = new JList<String>();
listUsers.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
scrollPane_2.setViewportView(listUsers);
lblRoomInfo = new JLabel("\u5728\u7EBF\u4EBA\u6570");
lblRoomInfo.setBounds(546, 413, 145, 18);
frmtcp.getContentPane().add(lblRoomInfo);
rdbtnBrocast = new JRadioButton("\u53D1\u9001\u7ED9\u6240\u6709\u4EBA");
buttonGroup.add(rdbtnBrocast);
rdbtnBrocast.setBounds(66, 306, 104, 22);
frmtcp.getContentPane().add(rdbtnBrocast);
rdbtnPrivateChat = new JRadioButton("\u79C1\u804A");
    buttonGroup.add(rdbtnPrivateChat);
rdbtnPrivateChat.setSelected(true);
rdbtnPrivateChat.setBounds(192, 306, 72, 22);
frmtcp.getContentPane().add(rdbtnPrivateChat);
// 更换样式
try {
String style = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
UIManager.setLookAndFeel(style);
// 更新窗体样式
SwingUtilities.updateComponentTreeUI(this.frmtcp);
} catch (Exception e) {
e.printStackTrace();
}
}

/*
protected String clear() {
// TODO Auto-generated method stub
return null;
}
*/
//内部类.客户端线程,负责与服务器交互


class ClientThread extends Thread {
private final Component frmtcp = null;


/**
* 通信套接字
*/
private  Socket socket;

/**
* 基本数据输入流
*/
private DataInputStream dis;

/**
* 基本数据输出流
*/
private DataOutputStream dos;

/**
* 是否登录
*/
private boolean isLogged;

/**
* 连接服务器并登录
*/
private void login() throws IOException{
// 获取服务器IP地址和端口
String serverIp = textServerIP.getText();
int serverPort = Integer.parseInt(textServerPort.getText());
// 连接服务器,获取套接字IO流
socket = new Socket(serverIp, serverPort);
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());
// 获取用户名,构建、发送登录报文
String username = textUsername.getText();
String msgLogin = "LOGIN#" + username;
dos.writeUTF(msgLogin);
dos.flush();
// 读取服务器返回的信息,判断是否登录成功
String response = dis.readUTF();

// 登录失败
if(response.equals("FAIL")) {
addMsg("登录服务器失败");
// 登录失败,断开连接,结束客户端线程
socket.close();
return;
}
// 登录成功
else {
addMsg("聊天室服务器登录成功");
isLogged = true;
btnConnect.setText("退出");
btnSend.setEnabled(true);
//更新Jlist列表信息
String[] self ={username};
updateJList(listUsers,self,"ADD");
//获取在线人数
lblRoomInfo.setText("目前在线人数"+listUsers.getModel().getSize()+"人");

}
}


//更新用户列表
public void updateJList(JList jList,String[] items,String op){
switch(op){
case "ADD": //添加新数据
for(int i=0;i<items.length;i++){
modelUsers.addElement(items[i]);
break;
}
case "DEL"://删除数据
for(int i=0;i<items.length;i++){
modelUsers.removeElement(items[i]);
break;

}
default:
break;
}
jList.setModel(modelUsers);//更新数据

}

//退出聊天室功能实现
public void logout(){
try {
Utils.sendMsg(socket, "LOGOUT#"+username);
// String msgLongout="LOGOUT";
//dos.writeUTF(msgLogout);
//dos.flush();
//isLogged=false;

//更新界面
modelUsers.clear();
listUsers.setModel(modelUsers);
addMsg("已经退出聊天室");
btnConnect.setText("登录");
btnSend.setEnabled(false);

String[] self ={username};
updateJList(listUsers,self,"ADD");
//获取在线人数
lblRoomInfo.setText("目前在线人数"+listUsers.getModel().getSize()+"人");
socket.close();
} catch (IOException e) {

e.printStackTrace();
}
}


//图片处理
public void sendPicture(ActionEvent e){
                                        
 //没有实现
}

//发送消息
public void sendChatMsg(){
String msgChat=null;
String dstUser="所有人";
if(rdbtnBrocast.isSelected()){
msgChat="TALKTO_ALL#"+textAreaMsg.getText();
}
if(rdbtnPrivateChat.isSelected()){
dstUser=(String)listUsers.getSelectedValue();
if(dstUser==null){
JOptionPane.showMessageDialog(this.frmtcp,"请选择需要私聊的用户!");
return;
}
//String toUsername=(String)listUsers.getSelectedValue();
msgChat="TALKTO#"+dstUser+"#"+textAreaMsg.getText();
}
//发送聊天报文到服务器
Utils.sendMsg(socket, msgChat);
//添加到消息记录框
addMsg(Utils.getTimeStr()+" (我对"+dstUser+")说:\n"+textAreaMsg.getText());
// textAreaMsg.setText("");
if(null!=msgChat){
try{
dos.writeUTF(msgChat);
dos.flush();
}catch(IOException e){
e.printStackTrace();
}
}

}


//线程主体
@Override
public void run() {
// 连接服务器并登录
try {
login();
} catch (IOException e) {
addMsg("连接登录服务器时出现异常");
e.printStackTrace();
return;
}
while(isLogged) {
try {
String msg = dis.readUTF();
// String msg=Utils.recvMsg(socket);
String[] parts = msg.split("#");
switch (parts[0]) {
// 处理服务器发来的用户列表报文
case "USERLIST":
//String[] users=new String[parts.length-1];
// System.arraycopy(parts, 1, users, 0, parts.length-1);
//updateJList(listUsers, users, "ADD");
String[] self ={username};
updateJList(listUsers,self,"ADD");
//获取在线人数
lblRoomInfo.setText("目前在线人数"+listUsers.getModel().getSize()+"人");
for(int i = 1; i< parts.length; i++) {
modelUsers.addElement(parts[i]);
}
lblRoomInfo.setText("目前在线共"+listUsers.getModel().getSize()+"人");
break;
// 处理服务器发来的新用户登录表报文
case "LOGIN":
modelUsers.addElement(parts[1]);
break;
case "LOGOUT":
modelUsers.removeElement(parts[1]);
//String[] logoutUser={parts[1]};
//updateJList(listUsers,logoutUser,"DEL");
lblRoomInfo.setText("目前在线共"+listUsers.getModel().getSize()+"人");
addMsg(Utils.getTimeStr()+" "+parts[1]+"退出聊室");
break;
case "TALKTO_ALL":

addMsg(Utils.getTimeStr()+parts[1]+" 跟所有人说:"+parts[2]);
break;
case "TALKTO":

addMsg(Utils.getTimeStr()+parts[1]+" 跟我说:"+parts[2]);
break;

default:
break;
}
} catch (IOException e) {
// TODO 处理异常
isLogged = false;
e.printStackTrace();
}
}
}

}

/**
* 添加消息到文本框textAreaRecord
* @param msg,要添加的消息
*/
private void addMsg(String msg) {
// 在文本区中添加一条消息,并加上换行
textAreaRecord.append(msg + "\n");
// 自动滚动到文本区的最后一行
textAreaRecord.setCaretPosition(textAreaRecord.getText().length());
}
}

代码有欠缺,还需要继续改正,发送图片的功能也没有实现,希望各位路过大侠指点迷津,互相学习。


猜你喜欢

转载自blog.csdn.net/weixin_42442713/article/details/80859657