客户端
Client
package Client;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Java聊天室客户端
*
* @author 郑黑脸
* @version 1.0
*/
//继承Thread类,使用多线程
public class Client extends Thread {
//创建客户端Socket对象
public Socket c_socket;
private Client_chatFrame c_chatFrame;
private Client_enterFrame c_enterFrame;
private Client_singleFrame c_singleFrame;
//创建数据输入流对象
public DataInputStream dis = null;
//创建数据输出流对象
public DataOutputStream dos = null;
//退出标记
private boolean flag_exit = false;
//定义线程id
private int threadID;
//Map集合存储单人聊天界面
public Map<String, Client_singleFrame> c_singleFrames;
//List集合存储即时在线用户信息
public List<String> username_online;
//List集合存储用户id
public List<Integer> clientuserid;
//初始化用户名
public String username = null;
//读到的信息
public String chat_re;
//getter, setter方法
public Client_chatFrame getC_chatFrame() {
return c_chatFrame;
}
public Client_singleFrame getC_singlFrame() {
return c_singleFrame;
}
public void setC_singlFrame(Client_singleFrame c_singlFrame) {
this.c_singleFrame = c_singlFrame;
}
public void setC_chatFrame(Client_chatFrame c_chatFrame) {
this.c_chatFrame = c_chatFrame;
}
public Client_enterFrame getC_enterFrame() {
return c_enterFrame;
}
public void setC_enterFrame(Client_enterFrame c_enterFrame) {
this.c_enterFrame = c_enterFrame;
}
public int getThreadID() {
return threadID;
}
public void setThreadID(int threadID) {
this.threadID = threadID;
}
public Client() {
//创建集合对象
c_singleFrames = new HashMap<String, Client_singleFrame>();
username_online = new ArrayList<String>();
clientuserid = new ArrayList<Integer>();
// signlechatuse = new ArrayList<String>();
}
public static void main(String[] args) {
Client client = new Client();
Client_enterFrame c_enterFrame = new Client_enterFrame(client);
client.setC_enterFrame(c_enterFrame);
//显示窗体
c_enterFrame.setVisible(true);
}
/**登录
*
* @param username 用户名
* @param hostIp 主机IP
* @param hostPort 主机端口
* @return
*
* 登录模块
* 加入登录错误提示功能
* 可提示的内容有:端口号错误,主机地址错误,连接服务异常
* 如果三项都输入正确,则返回true
*
*/
public String login(String username, String hostIp, String hostPort) {
this.username = username;
String login_mess = null;
try {
c_socket = new Socket(hostIp, Integer.parseInt(hostPort));
} catch (NumberFormatException e) {
login_mess = "连接的服务器端口号port为整数,取值范围为:1024<port<65535";
return login_mess;
} catch (UnknownHostException e) {
login_mess = "主机地址错误";
return login_mess;
} catch (IOException e) {
login_mess = "连接服务其失败,请稍后再试";
return login_mess;
}
return "true";
}
//显示聊天窗体
public void showChatFrame(String username) {
getDataInit();
c_chatFrame = new Client_chatFrame(this, username);
c_chatFrame.setVisible(true);
//将退出标记置为true
flag_exit = true;
//启动该聊天的线程
this.start();
}
//获取数据单元模块
//从输入流中获取数据,封装到通道
private void getDataInit() {
try {
dis = new DataInputStream(c_socket.getInputStream());
dos = new DataOutputStream(c_socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 重写run方法
* 加入判断功能
*/
public void run() {
while (flag_exit) {
try {
//从所包含的输入流中读取此操作的字节数
chat_re = dis.readUTF();
} catch (IOException e) {
flag_exit = false;
if (!chat_re.contains("@serverexit")) {
chat_re = null;
}
}
if (chat_re != null) {
if (chat_re.contains("@clientThread")) {
int local = chat_re.indexOf("@clientThread");
setThreadID(Integer.parseInt(chat_re.substring(0, local)));
try {
dos.writeUTF(username + "@login" + getThreadID() + "@login");
} catch (IOException e) {
e.printStackTrace();
}
} else {
if (chat_re.contains("@userlist")) {
c_chatFrame.setDisUsers(chat_re);
} else {
if (chat_re.contains("@chat")) {
c_chatFrame.setDisMess(chat_re);
} else {
if (chat_re.contains("@serverexit")) {
c_chatFrame.closeClient();
} else {
if (chat_re.contains("@single")) {
c_chatFrame.setSingleFrame(chat_re);
}
}
}
}
}
}
}
}
//传输错误
public void transMess(String mess) {
try {
dos.writeUTF(username + "@chat" + getThreadID() + "@chat" + mess + "@chat");
} catch (IOException e) {
e.printStackTrace();
}
}
//退出聊天
public void exitChat() {
try {
dos.writeUTF(username + "@exit" + getThreadID() + "@exit");
flag_exit = false;
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
}
}
//退出登录
public void exitLogin() {
System.exit(0);
}
//退出客户端
public void exitClient() {
flag_exit = false;
System.exit(0);
}
}
服务器端
Server
package Server;
public class Server {
private ServerFrame serverFrame;
private ServerThread serverThread;
public ServerFrame getServerFrame() {
return serverFrame;
}
public void setServerFrame(ServerFrame serverFrame) {
this.serverFrame = serverFrame;
}
public Server() {
}
//启动服务器
public void startServer() {
try {
serverThread = new ServerThread(serverFrame);
} catch (Exception e) {
System.exit(0);
}
serverThread.setFlag_exit(true);
serverThread.start();
}
//停止服务器
public void stopServer() {
synchronized (serverThread.messages) {
String str = "@serverexit";
serverThread.messages.add(str);
}
serverThread.serverFrame.setDisMess("@exit");
serverThread.serverFrame.setDisUsers("@exit");
serverThread.stopServer();
}
public static void main(String[] args) {
Server server = new Server();
ServerFrame serverFrame = new ServerFrame(server);
server.setServerFrame(serverFrame);
serverFrame.setVisible(true);
}
//关闭服务器
public void close() {
if (serverThread != null) {
if (serverThread.isAlive()) {
serverThread.stopServer();
}
}
System.exit(0);
}
}
ServerThread
package Server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
public class ServerThread extends Thread {
//服务端Socket对象
public ServerSocket serverSocket;
//信息 用Vector集合存储
public Vector<String> messages;
//用户线程 用Vector集合存储
public Vector<ClientThread> clients;
//Map集合存储用户信息
public Map<Integer, String> users;
//广播对象
public BroadCast broadcast;
//定义服务器端端口号
public int Port = 5000;
public boolean login = true;
public ServerFrame serverFrame;
private boolean flag_exit = false;
//服务器线程
public ServerThread(ServerFrame serverFrame) {
this.serverFrame = serverFrame;
//创建集合存储信息
messages = new Vector<String>();
clients = new Vector<ClientThread>();
users = new HashMap<Integer, String>();
try {
serverSocket = new ServerSocket(Port);
} catch (IOException e) {
this.serverFrame.setStartAndStopUnable();
System.exit(0);
}
//广播线程
broadcast = new BroadCast(this);
broadcast.setFlag_exit(true);
broadcast.start();
}
@Override
public void run() {
Socket socket;
//当标记为ture的时候检查服务器端Socket是否在开启状态,如果关闭,将标记置为false
while (flag_exit) {
try {
if (serverSocket.isClosed()) {
flag_exit = false;
} else {
try {
//监听客户端socket
socket = serverSocket.accept();
} catch (SocketException e) {
socket = null;
flag_exit = false;
}
//当客户端socket不为null时,启动客户端线程
if (socket != null) {
ClientThread clientThread = new ClientThread(socket, this);
clientThread.setFlag_exit(true);
clientThread.start();
synchronized (clients) {
clients.addElement(clientThread);
}
synchronized (messages) {
users.put((int) clientThread.getId(), "@login@");
messages.add(clientThread.getId() + "@clientThread");
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//停止服务器
public void stopServer() {
try {
if (this.isAlive()) {
serverSocket.close();
setFlag_exit(false);
}
} catch (Throwable e) {
}
}
//设置标记退出
public void setFlag_exit(boolean b) {
flag_exit = b;
}
}
ClientThread
package Server;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 客户端线程
*
* @author 郑黑脸
* @version 1.0
*
* 用户端线程的实现类
*/
public class ClientThread extends Thread {
//服务器客户端Socket对象
public Socket clientSocket;
//服务端线程对象
public ServerThread serverThread;
//数据输入流对象
public DataInputStream dis;
//数据输出流对象
public DataOutputStream dos;
//客户端用户ID
public String client_userID;
//标记
private boolean flag_exit = false;
//客户端Socket
public ClientThread(Socket socket, ServerThread serverThread) {
clientSocket = socket;
this.serverThread = serverThread;
try {
//封装数据输入输出流
dis = new DataInputStream(clientSocket.getInputStream());
dos = new DataOutputStream(clientSocket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
//重写run方法
@Override
public void run() {
while (flag_exit) {
try {
String Message = dis.readUTF();
if (Message.contains("@login")) {
//以@login分割userInfo字符串,得到Info
String[] userInfo = Message.split("@login");
int userID = Integer.parseInt(userInfo[1]);
serverThread.users.remove(userID);
if (serverThread.users.containsValue(userInfo[0])) {
for (int i = 0; i < serverThread.clients.size(); i++) {
int id = (int) serverThread.clients.get(i).getId();
if (serverThread.users.get(id).equals(userInfo[0])) {
serverThread.users.remove(id);
serverThread.users.put(id, userInfo[0] + "_" + id);
break;
}
}
serverThread.users.put(Integer.parseInt(userInfo[1]), userInfo[0] + "_" + userInfo[1]);
} else {
serverThread.users.put(userID, userInfo[0]);
}
Message = null;
//创建容器 存储线程id和userlist
StringBuffer sb = new StringBuffer();
synchronized (serverThread.clients) {
for (int i = 0; i < serverThread.clients.size(); i++) {
int threadID = (int) serverThread.clients.elementAt(i).getId();
sb.append((String) serverThread.users.get(new Integer(threadID)) + "@userlist");
sb.append(threadID + "@userlist");
}
}
String userNames = new String(sb);
serverThread.serverFrame.setDisUsers(userNames);
Message = userNames;
} else {
if (Message.contains("@exit")) {
String[] userInfo = Message.split("@exit");
int userID = Integer.parseInt(userInfo[1]);
serverThread.users.remove(userID);
Message = null;
StringBuffer sb = new StringBuffer();
synchronized (serverThread.clients) {
for (int i = 0; i < serverThread.clients.size(); i++) {
int threadID = (int) serverThread.clients.elementAt(i).getId();
if (userID == threadID) {
serverThread.clients.removeElementAt(i);
i--;
} else {
sb.append((String) serverThread.users.get(new Integer(threadID)) + "@userlist");
sb.append(threadID + "@userlist");
}
}
}
String userNames = new String(sb);
if (userNames.equals("")) {
serverThread.serverFrame.setDisUsers("@userlist");
} else {
serverThread.serverFrame.setDisUsers(userNames);
}
Message = userNames;
} else {
//聊天显示姓名和发送时间的实现
if (Message.contains("@chat")) {
String[] chat = Message.split("@chat");
StringBuffer sb = new StringBuffer();
SimpleDateFormat form = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = form.format(new Date());
sb.append(chat[0] + " " + date + "\n");
sb.append(chat[2] + "@chat");
String str = new String(sb);
Message = str;
serverThread.serverFrame.setDisMess(Message);
} else {
if (Message.contains("@single")) {
}
}
}
}
synchronized (serverThread.messages) {
if (Message != null) {
serverThread.messages.addElement(Message);
}
}
if (Message.contains("@exit")) {
this.clientSocket.close();
flag_exit = false;
}
} catch (IOException e) {
}
}
}
//关闭客户端线程,并提示服务器的客户端Socket为空
public void closeClienthread(ClientThread clientThread) {
if (clientThread.clientSocket != null) {
try {
clientThread.clientSocket.close();
} catch (IOException e) {
System.out.println("server's clientSocket is null");
}
}
try {
setFlag_exit(false);
} catch (Throwable e) {
e.printStackTrace();
}
}
public void setFlag_exit(boolean b) {
flag_exit = b;
}
}
BroadCast
package Server;
import java.io.IOException;
/**
* 广播线程的实现类
*
* @author 郑黑脸
*
* @version 1.0
*/
public class BroadCast extends Thread {
//客户端线程
ClientThread clientThread;
//服务器端线程
ServerThread serverThread;
String str;
private boolean flag_exit = false;
public BroadCast(ServerThread serverThread) {
this.serverThread = serverThread;
}
@Override
public void run() {
boolean flag = true;
while (flag_exit) {
synchronized (serverThread.messages) {
if (serverThread.messages.isEmpty()) {
continue;
} else {
str = (String) serverThread.messages.firstElement();
serverThread.messages.removeElement(str);
if (str.contains("@clientThread")) {
flag = false;
}
}
}
synchronized (serverThread.clients) {
for (int i = 0; i < serverThread.clients.size(); i++) {
clientThread = serverThread.clients.elementAt(i);
if (flag) {
try {
//向记录的每一个客户端发送数据信息
if (str.contains("@exit")) {
serverThread.clients.remove(i);
clientThread.closeClienthread(clientThread);
clientThread.dos.writeUTF(str);
}
if (str.contains("@chat") || str.contains("@userlist") || str.contains("@serverexit")) {
clientThread.dos.writeUTF(str);
}
if (str.contains("@single")) {
String[] info = str.split("@single");
int id_thread = Integer.parseInt(info[2]);
for (int j = 0; j < serverThread.clients.size(); j++) {
if (id_thread == serverThread.clients.get(j).getId()) {
serverThread.clients.get(j).dos.writeUTF(str);
i = serverThread.clients.size();
break;
}
}
}
} catch (IOException E) {
}
} else {
String value = serverThread.users.get((int) clientThread.getId());
if (value.equals("@login@")) {
flag = true;
try {
//向记录的每一个客户端发送数据信息
clientThread.dos.writeUTF(str);
if (str.contains("@exit")) {
serverThread.clients.remove(i);
clientThread.closeClienthread(clientThread);
}
} catch (IOException E) {
}
break;
}
}
}
}
if (str.contains("@serverexit")) {
serverThread.users.clear();
flag_exit = false;
}
}
}
public void setFlag_exit(boolean b) {
flag_exit = b;
}
public void stopBroadCase() {
flag_exit = false;
}
}