实现Java简单的聊天室

  所用主要知识:多线程+网络编程

    效果如下图

/**
*
* @author Administrator
*
* 简单的多人聊天系统——重点:同时性,异步性
* 1、客户端:发送消息,并且接收消息
* 1.1 消息发送至服务器:服务器每次都将客户发过来的信息发送到每个客户端
* 1.2 接收消息:发送的同时也要接收消息,所以必须有两个线程,一个发送消息,一个接收消息
* 1.3 关于这两个线程:如果没有线程,接收和发送就是按顺序执行的了,那么是发送后接收还是接收后发送?或者是
* 一边可以发送一边又可以接收呢?答案不言而喻
* 1.4 在客户端,用可以通过界面的点击按钮事件发送消息,所以就要开启一个线程来接收服务器发送给客户端的消息了
* 1.5 多线程:不需按步骤逐步循环,可以和其他程序同时执行,不相互干扰
* 2、服务器端:接收所有用户的消息并且借每个用户的消息发送给连接了服务器的客户端
* 2.1 服务器既要接收C端信息又要想所有C端发送信息,先收后发。一收就发。
* 2.2 S端还要显示C端上线提醒
* 2.3 上线提醒和收发信息是不影响的,互不干扰的,但是都要在S端上执行,如果没有线程,所以的程序都要按顺序执行了所以又要 多线程
* 2.4 一个线程负责向所以C端发送接收到的任何一条信息,一个线程负责显示C端上线的信息
*
* 3、类:S端:Server、ServerFrame、sendThread 三个类
* C端:Client、ClientFrame 两个类
*
*/

 package com.java.chat;

 import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List; import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea; public class Server {
//用于保存Socket的集合,也可以说是把个C端与S端的一个连接通道保存起来
//作用:服务器将接收到的信息发给集合里的所以socket,也就是发给每个C端
public static List<Socket> list = new ArrayList<Socket>(); public static void main(String[] args) {
new ServerFrame("服务器端");
} } /*
* 继承Jframe类表示该类可以创建一个窗口程序了,
* 实现ActionListener:动作监听,在S端点击“启动服务器”是要执行的代码
* 实现Runnable:实现多线程,该窗口是个客户端窗口,要开启一个线程接收显示服务器发过来的信息
*/
class ServerFrame extends JFrame implements ActionListener, Runnable { private static final long serialVersionUID = 1L; private ServerSocket serverSocket = null; private Socket socket; private JButton start;
private JTextArea message; public ServerFrame(String name) {
super(name); start = new JButton("启动服务器");
start.addActionListener(this);
message = new JTextArea();
message.setEditable(false);
this.add(start, "North");
this.add(message, "Center"); this.setResizable(false);
this.setBounds(0, 0, 400, 300);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
} @Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == start) {
// 如果点击的按钮是开始按钮。则启动服务器。
try {
serverSocket = new ServerSocket(6666);
message.setText("服务器已启动。。。"); //单击“启动服务器”开启一个线程用于获取用户上线的情况
new Thread(this).start(); } catch (IOException e1) {
e1.printStackTrace();
}
}
} //获取C端上线的情况
@Override
public void run() {
String address = null;
int port = 0;
//用一个死循环一直让S端开启接收C端的连接,将C端的IP和端口显示在面板上
//如果用循环的话就只能接收一次
while (true) {
try {
socket = serverSocket.accept();
Server.list.add(socket);
address = socket.getInetAddress().getHostAddress();
port = socket.getPort();
message.append("\r\nip/" + address + ":" + port + "\t上线了"); //开启转发信息的线程
new sendThread(socket).start(); } catch (IOException e) {
// System.out.println(address + ":" + port + "\t退出了服务器");
}
}
} } /*
* 接收每个C端的信息并向每个C端发送接收到的信息
*/
class sendThread extends Thread {
private Socket socket; public sendThread(Socket socket) {
super();
this.socket = socket;
} @Override
public void run() {
InputStream is = null;
BufferedReader br = null;
String str = null;
OutputStream os = null;
BufferedWriter bw = null;
while (true) {
try {
is = socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
str = br.readLine();
for (Socket s : Server.list) {
os = s.getOutputStream();
bw = new BufferedWriter(new OutputStreamWriter(os));
bw.write(str);
bw.newLine();
bw.flush();
}
} catch (IOException e) {
//如果断开连接则移除对于的socket
Server.list.remove(socket);
}
}
}
}

服务器端代码

 package com.java.chat;

 import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date; import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField; /**
*
* @author Administrator
*
*/ public class Client {
public static void main(String[] args) {
new ClientFrame("客户端");
}
} /*
* 继承Jframe类表示该类可以创建一个窗口程序了,
* 实现ActionListener:动作监听,就是一个事件发送后应该执行什么就要重新它的方法
* 实现Runnable:实现多线程,该窗口是个客户端窗口,要开启一个线程接收显示服务器发过来的信息
*/
class ClientFrame extends JFrame implements ActionListener, Runnable { private static final long serialVersionUID = 1L; private Socket socket;
OutputStream os = null;
BufferedWriter bw = null; JTextArea message;
JScrollPane scroll;
JTextField input;
JButton submit;
JPanel panel; String uname = "";
// 聊天页面
JPanel chat; // 登录页面
JPanel login;
JTextField username;
JButton ok; public ClientFrame(String name) {
super(name); message = new JTextArea();
message.setEditable(false);
scroll = new JScrollPane(message);
input = new JTextField(20);
submit = new JButton("发送");
panel = new JPanel(); panel.add(input);
panel.add(submit);
chat = new JPanel(new BorderLayout());
chat.add(scroll, "Center");
chat.add(panel, "South"); // 在创建客户端窗体是就要把客户端与服务端连接
try {
//127.0.0.1表示本机地址,地址好端口都可以改,这要看服务器那边是什么地址和端口
socket = new Socket("127.0.0.1", 6666);
os = socket.getOutputStream();
bw = new BufferedWriter(new OutputStreamWriter(os)); } catch (IOException e1) {
e1.printStackTrace();
} /* 在创建C端窗体的时候也应该开启一个线程接收显示来自服务器的信息
* 为什么要开启一个线程呢?因为在这个窗体里既要实现消息的发送,
* 也要接收信息,而且两个不能按顺序进行,也互不干扰,所以开启一个线程时时刻刻等着S端发来的信息
*/
//接收信息
new Thread(this).start(); //提交按钮工作监听器,点击提交时触发
submit.addActionListener(this); login = new JPanel();
username = new JTextField(20);
ok = new JButton("确定");
ok.addActionListener(this);
JLabel label = new JLabel("请输入用户名");
label.setFont(new Font(Font.DIALOG, Font.BOLD, 28));
label.setForeground(Color.red);
login.add(label);
login.add(username);
login.add(ok); this.add(chat);
this.add(login); this.setResizable(false);
this.setBounds(400, 100, 400, 300);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
} @Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == submit) {
// 如果点击提交按钮,则表示需要将信息发送出去。
String str = null;
//以下三行是创建发送时间的代码
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
String dateStr = format.format(date); str = uname+" "+dateStr+" "+input.getText(); try {
bw.write(str);
bw.newLine();
// System.out.println("客户端发送了:"+str);
bw.flush();
} catch (IOException e1) {
System.out.println("无法发送,服务器连接异常!");
} // System.out.println(str); } else if (e.getSource() == ok) {// 用户登录
uname = username.getText();// 获取文本框输入的文本信息
if ("".equals(uname)) {
JOptionPane.showMessageDialog(this, "用户名不能为空!");
} else {
login.setVisible(false);
chat.setVisible(true);
this.setTitle(uname + " 的客户端");
this.add(chat);
}
}
} //run方法里面的是接受S端信息和将信息显示的代码
@Override
public void run() {
BufferedReader br = null;
InputStream is = null;
String str = null;
try {
is = socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
while (true) {
str = br.readLine()+"\r\n";
message.append(str);
}
} catch (IOException e) {
System.out.println("无法发送,服务器连接异常!");
}
} }

客户端代码

(完)

Java简单聊天室的更多相关文章

  1. java web利用mvc结构实现简单聊天室功能

    简单聊天室采用各种内部对象不适用数据库实现. 一个聊天室要实现的基本功能是:         1.用户登录进入聊天室, 2.用户发言 3.用户可以看见别人发言 刚才算是简单的需求分析了,现在就应该是进 ...

  2. Java Socket聊天室编程(一)之利用socket实现聊天之消息推送

    这篇文章主要介绍了Java Socket聊天室编程(一)之利用socket实现聊天之消息推送的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下 网上已经有很多利用socket实现聊天的例子了 ...

  3. SpringBoot 搭建简单聊天室

    SpringBoot 搭建简单聊天室(queue 点对点) 1.引用 SpringBoot 搭建 WebSocket 链接 https://www.cnblogs.com/yi1036943655/p ...

  4. 基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍。最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室。

    基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍.最后我们将会实现一个基于S ...

  5. Python Socket 简单聊天室2

    上篇文章写了一个简单的单线程的一问一答的简单聊天室.这次我们使用SocketServer模块搭建一个多线程异步的聊天室. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ...

  6. Java Socket聊天室编程(二)之利用socket实现单聊聊天室

    这篇文章主要介绍了Java Socket聊天室编程(二)之利用socket实现单聊聊天室的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下 在上篇文章Java Socket聊天室编程(一)之 ...

  7. Asp.Net SignalR - 简单聊天室实现

    简单聊天室 使用持久链接类我们就可以做一些即时通讯的应用了,我使用Group做了一个简单的聊天室,先上图技术细节下面再讲 可以加入聊天室.创建聊天室.发送消息,下面就说说我是如何通过Group做出来的 ...

  8. ASP.NET SingalR + MongoDB 实现简单聊天室(一):搭建基本框架

    ASP.NET SingalR不多介绍.让我介绍不如看官网,我这里就是直接上源代码,当然代码还是写的比较简单的,考虑的也少,希望各位技友多多提意见. 先简单介绍聊天室功能: 用户加入聊天室,自动给用户 ...

  9. 利用socket.io+nodejs打造简单聊天室

    代码地址如下:http://www.demodashi.com/demo/11579.html 界面展示: 首先展示demo的结果界面,只是简单消息的发送和接收,包括发送文字和发送图片. ws说明: ...

随机推荐

  1. MFC中的多线程

    程序是计算机指令的几何,以文件的形式存在磁盘上.进程被定义为正在运行的程序的实例,是在进行地址空间中的一次执行活动.一个程序可以对应多个进程,如可以通过打开多个Word程序,每个word的应用就是一个 ...

  2. 软件工程:java实现wordcount基本功能

    github链接:https://github.com/Nancy0611/wc 一:项目相关要求 该项目能统计文本文件的字符数.单词数和行数.这个项目要求写一个命令行程序,模仿已有wc.exe 的功 ...

  3. Java动态代理(二)CGLIB动态代理应用

    JDK自从1.3版本开始,就引入了动态代理,JDK的动态代理用起来非常简单,但是它有一个限制,就是使用动态代理的对象必须实现一个或多个接口 .如果想代理没有实现接口的类可以使用CGLIB包. CGLI ...

  4. Visual Studio 2017(VS2017) 企业版 Enterprise 注册码

    Visual Studio 2017(VS2017) 企业版 Enterprise 注册码:NJVYC-BMHX2-G77MM-4XJMR-6Q8QF 终于等到你,最强 IDE Visual Stud ...

  5. RabbitMq初探——发布与订阅

    publish and subscribe 前言 前面的例子 我们都是用到的都是消息单一消费,即一条消息被单个消费者消费.像微博系统的消息推送,是一条消息推送给所有订阅到该频道的用户. 这里我们就需要 ...

  6. 375. 猜数字大小 II leetcode java

    题目: 我们正在玩一个猜数游戏,游戏规则如下: 我从 1 到 n 之间选择一个数字,你来猜我选了哪个数字. 每次你猜错了,我都会告诉你,我选的数字比你的大了或者小了. 然而,当你猜了数字 x 并且猜错 ...

  7. Spark Streaming初步使用以及工作原理详解

    在大数据的各种框架中,hadoop无疑是大数据的主流,但是随着电商企业的发展,hadoop只适用于一些离线数据的处理,无法应对一些实时数据的处理分析,我们需要一些实时计算框架来分析数据.因此出现了很多 ...

  8. “全栈2019”Java多线程第五章:线程睡眠sleep()方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  9. Mybatis 动态Sql语句《常用》

    MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦.拼接的时候要确保不能忘了必要的空格,还要注意省掉 ...

  10. Spring-解决请求中文乱码问题

    解决spring请求中文乱码问题 1.web.xml添加编码拦截器 <filter> <filter-name>CharacterEncoding</filter-nam ...