*接上期 Swing组件组合使用--登录界面源码(仿QQ)*,这期分享客户端与服务端源码
首先是服务端源码:**
import jdk.internal.icu.text.UnicodeSet;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class ServerChat {
//这是一个main方法,是程序的入口:
public static void main(String[] args) throws Exception {
ServerJframe serverJframe = new ServerJframe();
serverJframe.init();
}
}
class ServerJframe extends JFrame {
//GUI相关属性
JTextArea serverTa = new JTextArea();
int sum = 0;
JScrollPane scrollPane = new JScrollPane(serverTa);
JPanel btnTool = new JPanel();
JButton startBtn = new JButton("上班");
JButton stopBtn = new JButton("下班");
private Set<String> set = new HashSet<>();
//端口
private static final int PORT = 8888;
//ServerSocket
private ServerSocket serverSocket = null;
private Socket socket = null;
//Server接受数据
private DataInputStream dataInputStream = null;
// 多个客户端访问时,客户端对象存放入List中
private ArrayList<ClientCoon> ccList = new ArrayList<ClientCoon>();
// 服务器启动的标志 (其实ServerSocket ss 初始化出来时以为者服务器的启动)
private boolean isStart = false;
public void init() throws Exception {
this.setTitle("畅聊服务器端");
this.add(scrollPane, BorderLayout.CENTER);
btnTool.add(startBtn);
btnTool.add(stopBtn);
this.add(btnTool, BorderLayout.SOUTH);
this.setBounds(0, 0, 500, 500);
//判断服务器是否已经开启
if (isStart) {
System.out.println("服务器已经上班 了\n");
} else {
System.out.println("服务器还没有上班,请点击上班催催服务器上班!\n");
}
//按钮监听监听服务器开启,置开始位false
startBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
if (serverSocket == null) {
serverSocket = new ServerSocket(PORT);
}
isStart = true;
//startServer();
serverTa.append("服务器已经上班啦! \n");
System.out.println("服务器上班啦!!\n");
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
// 终止按钮监听停止服务器,置开始位true
stopBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
if (serverSocket != null) {
serverSocket.close();
isStart = false;
}
System.exit(0);
serverTa.append("服务器下班啦!!\n");
System.out.println("服务器下班啦!!\n");
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
/**
* 服务器窗口关闭应该停止服务器,需改进的代码
*/
// this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// serverTa.setEditable(false);
this.setVisible(true);
startServer();
}
/**
* 服务器启动代码
*/
public void startServer() throws Exception {
try {
try {
serverSocket = new ServerSocket(PORT);
isStart = true;
} catch (Exception e) {
e.printStackTrace();
}
// 可以接受多个客户端的连接
// 接每一個信息时,服务器不可以终断,所以将其写入while()中,判断符为服务器开关的判断符
while (isStart) {
socket = serverSocket.accept();
ccList.add(new ClientCoon(socket));
System.out.println("\n" + "有新的老板加入聊天室啦" + socket.getInetAddress() + "/" + socket.getPort() + "\n" + "当前在线人数:" + set.size());
// serverTa.append("\n" + "有新的老板加入聊天室啦" + socket.getInetAddress() + "/" + socket.getPort() + "\n" + "当前在线人数:" + set.size());
}
//服务器接受客户端一句话
/*receiveStream();*/
} catch (SocketException e) {
System.out.println("服务器下班干饭去啦!!!");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 服务器停止代码
* */
/**
* 服务器接受数据的方法(客户端传送一句话),不适用多个客户端进行通话
* */
/*public void receiveStream(){
try {
dataInputStream = new DataInputStream(socket.getInputStream());
String str = dataInputStream.readUTF();
System.out.println(str);
serverTa.append(str);
}catch (Exception e){
e.printStackTrace();
}
}*/
/**
* @deprecated 内部类声明 对象 这个对象是属于服务器端的一个连接对象
*/
class ClientCoon implements Runnable {
Socket socket = null;
public ClientCoon(Socket socket) {
this.socket = socket;
/**
* 线程启动在这里:
* 初始化方法里 初始化一个线程 ,线程中封装的是自己,做整个线程的调用
*/
(new Thread(this)).start();
}
//接受客户端信息(多线程run()方法)
@Override
public void run() {
try {
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
// 为了让服务器能够接受到每个客户端的多句话
while (isStart) {
//readUTF()是一种阻塞方法,接一句就执行完了,所以循环中
String str = dataInputStream.readUTF();
if (str.indexOf("3010151410") == 0) {
int point = str.indexOf("上线啦");
String s = str.substring(10, point);
set.add(s);
str = "服务器:" + str.substring(10)+"当前在线人数:"+set.size();
}
if (str.indexOf("closed") == 0) {
int point = str.indexOf("下线了");
String s = str.substring(6, point);
for (String ss : set) {
if (ss.equals(s)) {
set.remove(s);
break;
}
}
String members = "";
str = "服务器:" + str.substring(6)+"当前在线人数:"+set.size();
}
System.out.println("\n" + socket.getInetAddress() + "|" + socket.getPort() + "说" + str + "\n");
serverTa.append("\n" + str + "\n");
//服务器向每个客户端发送别的客户端发来的信息
// 遍历ccList,调用send方法,在客户端里接受应该是多线程的接受
String strSend = "\n" + str + "\n";
Iterator<ClientCoon> iterator = ccList.iterator();
while (iterator.hasNext()) {
ClientCoon clientCoon = iterator.next();
clientCoon.send(strSend);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 服务器向每個连接对象发送数据的方法
public void send(String str) {
try {
DataOutputStream dataOutputStream = new DataOutputStream(this.socket.getOutputStream());
dataOutputStream.writeUTF(str);
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端源码:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
public class ClientChat {
//这是一个main方法,是程序的入口:
public ClientChat(String name) {
ClientJframe clientJframe = new ClientJframe();
clientJframe.init(name);
}
}
class ClientJframe extends JFrame {
//GUI布局
//聊天记录显示区
private String name = "";
private JTextArea ta = new JTextArea(10, 20);
//聊天记录输入区
JScrollPane scrollPane = new JScrollPane(ta);
private JTextField tf = new JTextField(20);
//发送按钮
private JButton jb = new JButton("发送");
private JPanel jp = new JPanel();
//端口
// 静态常量主机端口号
private static final String CONNSTR = "127.0.0.1";
// 静态常量服务器端口号
private static final int CONNPORT = 8888;
private Socket socket = null;
//Client发送数据
private DataOutputStream dataOutputStream = null;
//客户端连接上服务器判断符号
private boolean isConn = false;
/**
* 无参的构造方法 throws HeadlessException
*/
public ClientJframe() throws HeadlessException {
super();
}
public void init(String name) {
this.setTitle("Boos洽谈室");
this.add(scrollPane,BorderLayout.CENTER);
jp.setLayout(new FlowLayout(FlowLayout.LEFT));
//设置底部面板
jp.setBounds(800, 800, 100, 100);
jp.setForeground(new Color(199, 58, 231));
//添加输入框和发送按钮
jp.add(tf);
jp.add(jb);
ta.setFont(new Font("方正粗黑宋简体",0,15));
ta.setForeground(new Color(222, 126, 39));
tf.setFont(new Font("黑体",0,13));
tf.setForeground(new Color(39, 42, 222));
jb.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String strSend = tf.getText();
// 去掉空格判断长度是否为空
if (strSend.trim().length() == 0) {
return;
}
//客户端信息strSend发送到服务器上
send(name+"说:"+strSend);
tf.setText("");
// ta.append(strSend + "\n");
}
});
this.add(jp,BorderLayout.SOUTH);
//this.add(tf, BorderLayout.SOUTH);
this.name = name;
this.setBounds(300, 300, 315, 500);
// 添加监听,使回车键可以输入数据(判断数据合法性),
// 并輸入到聊天框,换行
tf.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String strSend = tf.getText();
// 去掉空格判断长度是否为空
if (strSend.trim().length() == 0) {
return;
}
//客户端信息strSend发送到服务器上
send(name+"说:"+strSend);
tf.setText("");
//ta.append(strSend + "\n");
}
});
//关闭事件
this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowListener() {
@Override
public void windowOpened(WindowEvent e) {
}
@Override
public void windowClosing(WindowEvent e) {
send("closed"+name+"下线了");
dispose();
}
@Override
public void windowClosed(WindowEvent e) {
}
@Override
public void windowIconified(WindowEvent e) {
}
@Override
public void windowDeiconified(WindowEvent e) {
}
@Override
public void windowActivated(WindowEvent e) {
}
@Override
public void windowDeactivated(WindowEvent e) {
}
});
ta.setEditable(false);//聊天区域不可以输入
tf.requestFocus();//光标聚焦
try {
socket = new Socket(CONNSTR, CONNPORT);
isConn = true;
} catch (Exception e) {
e.printStackTrace();
}
send("3010151410"+name+"上线啦!");
// 启动多线程
new Thread(new Receive()).start();
this.setVisible(true);
}
/**
* 客户端发送信息到服务器上的方法
*/
public void send(String str) {
try {
dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF(str);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* @deprecated 多线程的类,实现了Runnable接口的类
*/
class Receive implements Runnable {
@Override
public void run() {
try {
while (isConn) {
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
String str = dataInputStream.readUTF();
//通讯消息
ta.append(str);
}
} catch (SocketException e) {
System.out.println("服务器意外提前下班了!");
ta.append("服务器意外提前下班了!");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}