TCP聊天室实现了私聊、群聊和清屏的功能,简陋的UI界面,一个服务器端,支持多个客户端之间的通信。
项目代码:https://pan.baidu.com/s/17iegRam4KnWvcWHw3mvpxg 提取码:e8gx
服务器端:
可以开多个客户端进行客户端之间的通信。
客户端:
系统功能简介:
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);