简单的java聊天室(基于java socket)
该聊天室实现多个用户间聊天通信的问题。
ChatSocket
public class ChatSocket implements Runnable{
private Socket socket = null;
private DataInputStream inputStream = null;
private DataOutputStream outputStream = null;
public DataInputStream getInputStream() {
return inputStream;
}
public DataOutputStream getOutputStream() {
return outputStream;
}
public ChatSocket(Socket socket) {
this.socket = socket;
try {
inputStream = new DataInputStream(socket.getInputStream());
outputStream = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void send(String send) { //向客户端发送数据
try {
outputStream.writeUTF(send);
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() { //循环读取客户端发来的数据
String accept = null;
while (true) {
try {
accept = inputStream.readUTF();
ClientMannager.sendAll(this, accept);
} catch (IOException e) {
ClientMannager.sockets.remove(this);
}
}
}
}
ClientMannager
import java.util.Vector;//动态数组Vector,它对数据传输帮助很大
//用户端管理器
public class ClientMannager {
private ClientMannager() {//对ClientMannager构造方法,且为私有
}
public static Vector<ChatSocket> sockets = new Vector<>();
public static void sendAll(ChatSocket chatSocket, String send) {
for (ChatSocket socket : sockets) {
if (!chatSocket.equals(socket)) {//朝其他用户发送数据
socket.send(send);
}
}
}
}
ClientView
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.*;
@SuppressWarnings("serial")
public class ClientView extends JFrame implements ActionListener, KeyListener, Runnable {
private JTextArea textArea;//文本域
private JTextField textField, tfName;//输入框
private JButton btnSend, btnId;//选择按钮
private JLabel label;//标签
private JPanel jp1, jp2;//容器
public boolean isConnect = false;//是否连接标志
private Socket socket = null;
private DataInputStream inputStream = null;
private DataOutputStream outputStream = null;
//private DataInputStream flistI = null;
//private DataOutputStream flistO = null;
private JScrollPane scrollPane;//滚动条
private static ClientView view;
private JTextArea friend;
public JTextArea getTextArea() {//获取文本域
return textArea;
}
public DataInputStream getInputStream() {//读取数据
return inputStream;
}
public DataOutputStream getOutputStream() {//输出数据
return outputStream;
}
public static void main(String[] args) {//主函数启动程序
view = new ClientView();//启动客户端界面
ServiceView.clientViews.add(view);//客户端加载到服务器中
Thread thread = new Thread(view);//开启多个服务器
thread.start();
}
public ClientView() {
initView();
try {
socket = new Socket("localhost", 9090);//连接本地服务器
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void initView() {//客户端页面布局
textArea = new JTextArea(20, 20);//文本域
textArea.setEditable(false);
friend=new JTextArea(10,20);
scrollPane = new JScrollPane(textArea);//加入滚动条
textField = new JTextField(15);//输入框
textField.addKeyListener(this);//监听输入框
btnSend = new JButton("发送");//发送按钮
btnSend.addActionListener(this);//监听发送按钮
label = new JLabel("账号:");
tfName = new JTextField(8);
jp1 = new JPanel();
jp2 = new JPanel();
jp1.add(label);
jp1.add(tfName);
//tfName.setText("用户0");
jp1.setLayout(new FlowLayout(FlowLayout.CENTER));//本人信息
jp2.add(textField);
jp2.add(btnSend);
jp2.setLayout(new FlowLayout(FlowLayout.CENTER));//发送信息
add(jp1, BorderLayout.NORTH);//顶部展示本人
add(friend,BorderLayout.EAST);
add(scrollPane, BorderLayout.CENTER);//中部展示聊天内容
add(jp2, BorderLayout.SOUTH);//底部展示发送信息
setTitle("聊天室");
setSize(500, 500);
setLocation(450, 150);
setVisible(true); //画出界面
setDefaultCloseOperation(EXIT_ON_CLOSE);//关闭聊天框
addWindowListener(new WindowAdapter() { //窗口关闭后断开连接
@Override
public void windowClosing(WindowEvent e) {
try {
if (socket != null)
socket.close(); //关闭三个连接
if (inputStream!= null)
inputStream.close(); //关闭三个连接
if (outputStream != null)
outputStream.close();//关闭三个连接
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
}
public void actionPerformed(ActionEvent e) {//点击按钮发送信息
if (e.getSource() == btnSend) {
sendMsg();
}
}
private void sendMsg() {
try {
String s = textField.getText();
if (!s.equals("")) { //发送数据
textField.setText(""); //按一定格式组成我的显示信息
textArea.append("我(" + tfName.getText() + "):\r\n" + s + "\r\n");
outputStream = new DataOutputStream(socket.getOutputStream());
outputStream.writeUTF(tfName.getText() + "#" + s);//从管道中读取数据
outputStream.flush();//清除缓冲
//flistO = new DataOutputStream(socket.getOutputStream());
// flistO.writeUTF(tfName.getText() + "#" + s);//从管道中读取数据
//outputStream.flush();//清除缓冲
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void keyPressed1(KeyEvent arg0) {//通过换行键发送信息
if (arg0.getKeyCode() == KeyEvent.VK_ENTER) {
sendMsg();
}
}
public void keyTyped(KeyEvent arg0) {
}
@Override
public void run() {//显示他人传入的信息
try {
inputStream = new DataInputStream(socket.getInputStream());
while (true) {
String[] s = inputStream.readUTF().split("#");
textArea.append(s[0] + ":\r\n" + s[1] + "\r\n");
friend.append(s[0]+"\n");
}
} catch (IOException e) {
}
}
//public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
//}
///@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
}
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
//@Override
//public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
//}
}
Service
public class Service implements Runnable{
//ClientMannager a=new ClientMannager();
private ServerSocket serverSocket = null;//服务器端
public ServerSocket getServerSocket() {
return serverSocket;
}
@Override
public void run() {
try {
serverSocket = new ServerSocket(9090); //创建端口
while (true) { //循地接收客户端的连接
Socket socket = serverSocket.accept();
JOptionPane.showMessageDialog(ServiceView.getView(), "客户端连接端口", "TIP", JOptionPane.INFORMATION_MESSAGE);//消息提示器
ChatSocket chatSocket = new ChatSocket(socket); //新客户端连接
ClientMannager.sockets.add(chatSocket); //往客户端管理器里添加客户
Thread thread = new Thread(chatSocket);
thread.start();
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("服务器关闭");
}
}
}
ServiceView
public class ServiceView extends JFrame implements ActionListener{
private JButton btnOpen, btnStop;//打开,关闭按钮
private JLabel label;
private Service service = null;
public static ArrayList<ClientView> clientViews = new ArrayList<>();
private static ServiceView view;
public static ServiceView getView() {
return view;
}
public static void main(String[] args) {
view = new ServiceView();//从view开始调动整个程序
}
public ServiceView() {//构造函数
initView();
}
private void initView() {
btnOpen = new JButton("打开服务器");
btnStop = new JButton("关闭服务器");
btnStop.setEnabled(false);
btnOpen.addActionListener(this);
btnStop.addActionListener(this);
label = new JLabel("服务器停止工作");
add(label);
add(btnOpen);
add(btnStop);
setTitle("服务器");
setLayout(new GridLayout(3, 1, 0, 10));
setSize(300, 300);
setLocation(450, 150);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(btnOpen) ) {
open();
}
else {
stop();
}
}
public void open() { //开启服务器
service = new Service();
Thread thread = new Thread(service);
thread.start();
label.setText("服务器正在运行");
btnOpen.setEnabled(false);
btnStop.setEnabled(true);
}
public void stop() { //关闭服务器
label.setText("服务器已关闭");
btnOpen.setEnabled(true);
btnStop.setEnabled(false);
try {
synchronized (ClientMannager.sockets) { //关闭各个连接
for (ChatSocket socket : ClientMannager.sockets) {
socket.getInputStream().close();
socket.getOutputStream().close();
}
ClientMannager.sockets.removeAllElements();
}
for (ClientView view : clientViews) {
view.getInputStream().close();
view.getOutputStream().close();
}
service.getServerSocket().close();
} catch (IOException e) {
e.printStackTrace();
}
}
//@Override
//public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
//}
}
待完善的问题
1.代码写得条理不清晰,各个块的功能较混乱。应将功能打包,规范化。关键是要多加注释!!!
2.若是先关闭服务器端或先开启客户端都会出现bug,这里不够完善;
3.服务器端未能实现对客户端的强大管理功能。