//登陆界面
package com.konghao.netGUI05;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class LoginFrame extends JFrame {
private JButton jb; //登陆按钮
private JTextField jtf;//输入框
private JLabel jl;//"用户名"
public static void main(String[] args) {
new LoginFrame();
}
//界面关闭方法
public void close(){
this.setVisible(false);
}
public LoginFrame() {
this.setSize(350,100);
this.setLocation(500, 500);
this.setResizable(false);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setTitle("登陆");
jb = new JButton("登陆");
jtf = new JTextField(12);
jl = new JLabel("请输入用户名:");
jtf.addKeyListener(new KeyClick());
this.add(jl);this.add(jtf);this.add(jb);
this.setLayout(new FlowLayout());
//添加事件
jb.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String name = jtf.getText();
if(name==null||name.trim().equals("")){
JOptionPane.showMessageDialog(null, "用户名不能为空!");
return;
}
new ClientFrame(name);
close();
}
});
this.setVisible(true);
}
private class KeyClick extends KeyAdapter{
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_ENTER){
String name = jtf.getText();
if(name==null||name.trim().equals("")){
JOptionPane.showMessageDialog(null, "用户名不能为空!");
return;
}
new ClientFrame(name);
close();
}
}
}
}
//客户端
package com.konghao.netGUI05;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.*;
import javax.swing.DefaultListModel;
import javax.swing.*;
@SuppressWarnings("serial")
public class ClientFrame extends JFrame{
// public static void main(String[] args) {
// new ClientFrame();
// }
private JTextArea jta; //中央信息区域
private JList<String> list; //当前用户列表
private JScrollPane jsp1,jsp2; //滚动条
private JPanel jp;//底部容器
private JTextField jtf;//信息输入框
private JButton jb;//发送按钮
private JLabel jl;
private String name;
private boolean stop = false;
private Socket s;
private PrintWriter out;
private BufferedReader br;
private DefaultListModel<String> model ;
private List<String> users_selected = null;
public ClientFrame(String name) {
this.name = name;
this.setTitle("局域网聊天:"+name);
this.setSize(600,500);
this.setLocation(300, 300);
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
out.println(Server.DISCONNECT_TOKEN);
}
});
jta = new JTextArea();
jsp1 = new JScrollPane(jta);
list = new JList<String>();
list.setBackground(Color.GREEN);
jsp2 = new JScrollPane(list);
model = new DefaultListModel<String>();
list.setModel(model);
jp = new JPanel();
jtf = new JTextField(18);
jb = new JButton("发送");
jl = new JLabel("请输入消息:");
list.setFixedCellWidth(100);
new BorderLayout();
this.add(jsp2,BorderLayout.WEST);
this.add(jsp1);
jp.add(jl);jp.add(jtf);jp.add(jb);
new BorderLayout();
this.add(jp,BorderLayout.SOUTH);
jb.addActionListener(new BottonClick());
jtf.addKeyListener(new KeyPressed());
connect();
this.setVisible(true);
}
//连接方法
public void connect() {
try {
s = new Socket(Server.HOST,Server.PORT);
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
out = new PrintWriter(s.getOutputStream(),true);
out.println(name);
new Thread(new ReceiveThread()).start();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//接收服务器信息线程
public class ReceiveThread implements Runnable{
@Override
public void run() {
try {
while(true){
if(stop){
break;
}
receive();
}
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
} finally{
try {
if(s!=null) s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//接收方法
public void receive() throws IOException{
String str = br.readLine();
if(Server.DISCONNECT_TOKEN.equals(str)){
close();
return;
}
if(str.startsWith(Server.USER_FLAG)){
addList(str);
return;
}
addArea(str); //将接收到的信息添加到信息区
}
//点击用户列表时获得用户;
public String getUsers(){
users_selected = new ArrayList<String>();
users_selected = list.getSelectedValuesList();
String str = Server.TOKEN_START;
if(!users_selected.isEmpty()){
for(String users:users_selected){
if(users.equals("所有人")){
users_selected.remove(users);
return str+Server.TOKEN_ALL+Server.TOKEN_END;
}else{
str+=(users+","); // to: XXX,XXX,XX,:endmsg;
}
}
}else{
str+=Server.TOKEN_ALL;
}
return str+Server.TOKEN_END;
}
//将用户列表添加到List的方法
public void addList(String str){
model.removeAllElements();
String us = str.substring(Server.USER_FLAG.length());
String[] usr = us.split(",");
model.addElement("所有人");
for(String u : usr){
model.addElement(u);
}
}
//将信息添加到TextArea的方法
public void addArea(String msg){
jta.setText(jta.getText()+msg+"\n");
}
//关闭方法
public void close(){
stop = true;
}
//给服务器发送信息方法
public void send(){
String msg = jtf.getText();
if(msg==null||msg.trim().equals("")){
jtf.setText("");
return;
}
out.println(getUsers()+msg);
jtf.setText("");
}
//点击按钮事件
private class BottonClick implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource()==jb){
send();
}
}
}
//点击回车键事件
private class KeyPressed extends KeyAdapter{
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_ENTER){
send();
}
}
}
}
//服务端
package com.konghao.netGUI05;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Server {
public static final String HOST = "127.0.0.1";
public static final int PORT = 6060;
public static final String DISCONNECT_TOKEN = "disconnect";
public static final String USER_FLAG = "users:";
public static final String TOKEN_START = "to:";
public static final String TOKEN_END = ":end";
public static final String TOKEN_ALL = "allOfClients";
private boolean stop = false;
private Map<String,ServerThread> clients;
public static void main(String[] args) {
new Server().startup();
}
public void startup(){
ServerSocket ss = null;
clients = new HashMap<String,ServerThread>(); //初始化不能放在while循环之中,否则每次添加都是一个
//新的列表。
try {
ss = new ServerSocket(PORT);
System.out.println("The Server is ready!");
while(true){
Socket s = ss.accept();
ServerThread st = new ServerThread(s);
new Thread(st).start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(ss!=null) ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class ServerThread implements Runnable{
private Socket s;
private BufferedReader br = null;
private PrintWriter out = null;
private String name;
public ServerThread(Socket s) throws IOException {
this.s = s;
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
out = new PrintWriter(s.getOutputStream(),true);
name = br.readLine()+"["+s.getInetAddress().getHostAddress()+"]";
clients.put(name,this);
send( "--------[系统消息:"+name+"上线了!]----------");
sendUsers(); // 将用户列表传给客户端
}
//从信息中分离出用户信息
public String[] getUsers_selected(String msg){
String str = msg.substring(TOKEN_START.length(), msg.indexOf(TOKEN_END));
String[] us = str.split(",");
return us;
}
//从信息中分离出消息
public String format(String msg){
String str = msg.substring(msg.indexOf(TOKEN_END)+TOKEN_END.length());
return str;
}
//给客户端反馈信息
public void send(String msg){
Set<String> keys = clients.keySet();
boolean isAll =false;
if(msg.startsWith(TOKEN_START)){
String msg2 = format(msg); //分离出的消息
String[] uss = getUsers_selected(msg); //分离出的用户
for(String u : uss){
if(u.equals(TOKEN_ALL)){
isAll = true;
}
}
if(isAll){
for (String st : keys) {
clients.get(st).out.println(name+":"+msg2+"[公]");
}
}else{
for(String u : uss){
clients.get(u).out.println(name+":"+msg2+"[私]");
}
}
}else{
for (String st : keys) {
clients.get(st).out.println(msg);
}
}
}
//给客户端发送用户信息
public void sendUsers(){
String us = USER_FLAG;
Set<String> keys = clients.keySet();
for (String st : keys) {
us+=(st+",");
}
send(us);
}
@Override
public void run() {
try {
while(true){
if(stop){
break;
}
String str = br.readLine();
if(DISCONNECT_TOKEN.equals(str)){
stop();
break;
}
send(str);
//System.out.println(name+":"+str);
}
} catch (SocketException e){
stop();
} catch (IOException e) {
e.printStackTrace();
} finally{
try {
if(s!=null) s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//停止方法
public void stop(){
stop = true;
out.println(DISCONNECT_TOKEN);
clients.remove(name);
sendUsers();
send("--------[系统消息:"+name+"已经退出!]---------");
}
}
}
BUG: 每次打开多个客户端后再关闭其中一个,就会遇到。
BUG解决办法: