Java 综合应用程序的开发(多人聊天室)
程序员文章站
2022-03-19 15:59:26
编写一个 Java 应用程序,实现图形界面多人聊天室(多线程实现),要求聊天室窗口标题是 “欢迎使用 XXX 聊天室应用”,其中 XXX 是自己的班级姓名学号,如“软件 171 张三 1234”。...
一、 实验目的
熟悉 Java 综合应用程序的开发。
二、 实验任务
编写一个 Java 应用程序,实现图形界面多人聊天室(多线程实现),要求聊天室窗口标题是 “欢迎使用 XXX 聊天室应用”,其中 XXX 是自己的班级姓名学号,如“软件 171 张三 1234”。
客户端代码 ( ClientChat.java)
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.Socket;
import java.net.SocketException;
import java.util.*;
public class ClientChat extends JFrame { //客户端窗口
private JTextArea jTextArea = new JTextArea(10,20); //文本区域
private JScrollPane jScrollPane = new JScrollPane(jTextArea); //为文本区域加滚动条
private JTextField jTextField = new JTextField(20); //输入文本框
private static final String CONNSTR = "127.0.0.1";
private static final int CONNPORT = 8888; //服务器端口号
private Socket socket = null;
private DataOutputStream dataOutputStream = null; //设置一个管子
private boolean isConn = false;
public ClientChat() throws HeadlessException{
super();
}
public void init(String name){
this.setTitle("欢迎使用"+name+"聊天室应用");
this.add(jScrollPane, BorderLayout.CENTER); //把文本区放在中间
this.add(jTextField,BorderLayout.SOUTH); //把输入文本框放在南边
this.setBounds(300,300,550,400); //设计大小
jTextField.addActionListener(new ActionListener() { //对文本区设计一个监听
@Override
public void actionPerformed(ActionEvent e) {
String strSend = jTextField.getText();
//strSend发送到服务器上
if(strSend.trim().length() == 0){ //如果去掉两头空格长度等于0表明为空不能输出
return;
}
send(strSend);
jTextField.setText(""); //写完后消失(等于变成空字符串)
//jTextArea.append(strSend+'\n'); //往文本区添加输入的内容和换行
}
});
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //点击关闭按钮关闭程序
jTextArea.setEditable(false); //设计文本区域不能编辑
jTextField.requestFocus(); //光标聚焦在输入文本框
try { //处理抛出异常
socket = new Socket(CONNSTR,CONNPORT);
isConn = true; //表示连上服务器
} catch (IOException e) {
e.printStackTrace();
}
this.setVisible(true); //可视
Thread thread = new Thread(new Receive()); //改了
thread.setName(name);
thread.start(); //启动客户端多线程
}
//发送信息到服务器上的方法
public void send(String str){
try{
dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF(str);
}catch (IOException e){
e.printStackTrace();
}
}
//多线程类,实现了Runnable接口
class Receive implements Runnable{
@Override
public void run() {
try {
while(isConn) {
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
String str = dataInputStream.readUTF();
jTextArea.append(str);
}
} catch (SocketException e) {
System.out.println("服务器中断!!!");
jTextArea.append("服务器中断!! \n");
}
catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String []args){
Scanner input = new Scanner(System.in);
System.out.println("请输入你的昵称例如(网络191张飞龙)");
String name = input.nextLine();
ClientChat clientChat = new ClientChat();
clientChat.init(name);
}
}
服务端代码 ( ServerChat.java)
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Iterator;
public class ServerChat extends JFrame { //服务端(基于TCP的socket编程)
private static final int PORT = 8888; //设计一个端口常量
private JTextArea jTextArea = new JTextArea(); //文本区(用于显示客户端显示连接)
private JScrollPane jScrollPane = new JScrollPane(jTextArea); //为文本区域加滚动条
private JPanel jPanel = new JPanel(); //设置一个面板方便放置两个按钮
private JButton jButton1 = new JButton("启动"); //两个按钮(启动,停止)
private JButton jButton2 = new JButton("停止");
private ServerSocket serverSocket = null;
private ArrayList<ClientConn> ccList = new ArrayList<ClientConn>(); //创建一个线程数组
private boolean isStart = false; //用于判断是否启动
public ServerChat(){
this.setTitle("服务器端");
this.add(jScrollPane, BorderLayout.CENTER); //文本区放中间
jPanel.add(jButton1);
jPanel.add(jButton2);
this.add(jPanel,BorderLayout.SOUTH); //把两个按钮放在南边(FlowLayout布局)
this.setBounds(0,0,500,500);
if(isStart){
jTextArea.append("服务器已经启动了! \\n");
}else {
jTextArea.append("服务器还没启动,请点击启动按钮! \\n\\n");
}
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
isStart = false;
try {
if(serverSocket != null){
serverSocket.close();
}
System.out.println("服务器停止!");
jTextArea.append("服务器断开!");
System.exit(0);
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
});
jButton2.addActionListener(new ActionListener() { //为停止按钮设计监听
@Override
public void actionPerformed(ActionEvent e) {
isStart = false;
try {
if(serverSocket != null){
serverSocket.close();
isStart = false;
}
System.exit(0);
jTextArea.append("服务器断开!");
System.out.println("服务器停止!");
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
});
jButton1.addActionListener(new ActionListener() { //为启动按钮设计监听
@Override
public void actionPerformed(ActionEvent e) { //处理startServer()方法抛出的异常
System.out.println("hhhh");
try{
//isStart = true; //标置启动了
if(serverSocket == null){
serverSocket = new ServerSocket(PORT);
}
isStart = true;
jTextArea.append("服务器已经启动!"+"\n");
}catch (IOException e1){
e1.printStackTrace();
}
}
});
this.setVisible(true);
startServer();
}
//服务器的启动方法
public void startServer() {
try{
try{
serverSocket = new ServerSocket(PORT);
isStart = true;
}catch (IOException e2){
e2.printStackTrace();
}
//可以接收多个客户端的连接
while(isStart) {
Socket socket = serverSocket.accept();
ccList.add(new ClientConn(socket));
System.out.println("一个客户端连接服务器:" + socket.getInetAddress() + "/" + socket.getPort());
jTextArea.append("一个客户端连接服务器:" + socket.getInetAddress() + "/" + socket.getPort()+"\n");
}
//reciveStr();
}catch (SocketException e){
System.out.println("服务器中断!!!");
}
catch (IOException e){
e.printStackTrace();
}
}
//这个对象是属于服务器端的一个连接对象
class ClientConn implements Runnable{
Socket socket = null;
public ClientConn(Socket socket){ //把连接传过来
this.socket = socket;
(new Thread(this)).start(); //启动线程
}
//对于客户端应该是多线程的(同时接收客户端信息的)-多线程接收数据
public void run(){ //重写run()方法
try {
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream()); //设置一条管子
//为了让服务器能够接收到每个客户端的多条信息
while(isStart) {
String str = dataInputStream.readUTF();
System.out.println(socket.getInetAddress()+"|"+socket.getPort()+"说:"+str + "\n");
jTextArea.append(socket.getInetAddress()+"|"+socket.getPort()+"说:"+str + "\n");
String strSend =socket.getInetAddress()+"|"+socket.getPort()+"说:"+str + "\n";
//需要遍历ccList,调用send()方法,在客户端接受信息也是多线程接受
Iterator<ClientConn> it = ccList.iterator();
while(it.hasNext()){
ClientConn o = it.next();
o.send(strSend);
}
}
} catch (SocketException e) {
System.out.println("一个客户端下线了");
jTextArea.append(socket.getInetAddress()+"|"+socket.getPort()+"客户端下线了");
}
catch (IOException e) {
e.printStackTrace();
}
}
//每个连接对象发送数据的方法
public void send(String str){
try {
DataOutputStream dataOutputStream = new DataOutputStream(this.socket.getOutputStream());
dataOutputStream.writeUTF(str);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String []args){
ServerChat serverChat = new ServerChat();
}
}
1.先运行服务端代码(ServerChat.java)并点击启动按钮
2.多次运行客户端代码(ClientChat.java)这次以运行三次为例,每运行一次代码就创建一个线程。(先在控制台输入名称,才弹出窗口)
3.发送信息检测代码
4 .关闭客户端窗口退出该线程,剩下的人还能说话
5.停止服务端
本文地址:https://blog.csdn.net/weixin_49035831/article/details/111935219
下一篇: 真的用不上,排序算法