Java简单聊天室
实现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简单聊天室的更多相关文章
- java web利用mvc结构实现简单聊天室功能
简单聊天室采用各种内部对象不适用数据库实现. 一个聊天室要实现的基本功能是: 1.用户登录进入聊天室, 2.用户发言 3.用户可以看见别人发言 刚才算是简单的需求分析了,现在就应该是进 ...
- Java Socket聊天室编程(一)之利用socket实现聊天之消息推送
这篇文章主要介绍了Java Socket聊天室编程(一)之利用socket实现聊天之消息推送的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下 网上已经有很多利用socket实现聊天的例子了 ...
- SpringBoot 搭建简单聊天室
SpringBoot 搭建简单聊天室(queue 点对点) 1.引用 SpringBoot 搭建 WebSocket 链接 https://www.cnblogs.com/yi1036943655/p ...
- 基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍。最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室。
基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍.最后我们将会实现一个基于S ...
- Python Socket 简单聊天室2
上篇文章写了一个简单的单线程的一问一答的简单聊天室.这次我们使用SocketServer模块搭建一个多线程异步的聊天室. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ...
- Java Socket聊天室编程(二)之利用socket实现单聊聊天室
这篇文章主要介绍了Java Socket聊天室编程(二)之利用socket实现单聊聊天室的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下 在上篇文章Java Socket聊天室编程(一)之 ...
- Asp.Net SignalR - 简单聊天室实现
简单聊天室 使用持久链接类我们就可以做一些即时通讯的应用了,我使用Group做了一个简单的聊天室,先上图技术细节下面再讲 可以加入聊天室.创建聊天室.发送消息,下面就说说我是如何通过Group做出来的 ...
- ASP.NET SingalR + MongoDB 实现简单聊天室(一):搭建基本框架
ASP.NET SingalR不多介绍.让我介绍不如看官网,我这里就是直接上源代码,当然代码还是写的比较简单的,考虑的也少,希望各位技友多多提意见. 先简单介绍聊天室功能: 用户加入聊天室,自动给用户 ...
- 利用socket.io+nodejs打造简单聊天室
代码地址如下:http://www.demodashi.com/demo/11579.html 界面展示: 首先展示demo的结果界面,只是简单消息的发送和接收,包括发送文字和发送图片. ws说明: ...
随机推荐
- C的打印输出格式
#include<stdio.h> int main() { float test1=12.3224356546565461-0.1; int test2=13; char test3[] ...
- 深海划水队项目--七天冲刺之day7
站立式会议: 昨天已完成的工作:设置游戏按键,检查重合.检查是否超出边界.检查是否可以下落,方块的硬下落和软下落方法. 今日已完成的工作:添加方法:方块的着陆和消除. 工作中遇到的困难:在消除方块的时 ...
- Android-自定义控件-继承View与ViewGroup的初步理解
继承View需要走的流程是: 1.构造实例化, public ChildView(Context context, @Nullable AttributeSet attrs) 2.测量自身的高和宽on ...
- mybatis如何直接 执行传入的任意sql语句 并按照顺序取出查询的结果集
需求: 1.直接执行前端传来的任何sql语句,parameterType="String", 2.对于任何sql语句,其返回值类型无法用resultMap在xml文件里配置或者返回 ...
- Unity3d之Coroutine
在Unity3d中使用C#时,Coroutine是一个大有用处的好东西,至于怎么用网上多的是讲,我仅在此记录最近一次使用中的小发现. 因为某种需求,要在一个Coroutine实现中使用while循环, ...
- Rest-assured 写日志到 log4j
背景: 采用Rest-assured,日志采用log4j,发现Rest-assured本身只支持打印日志到控制台,但期望打印到文件中以便排查问题 请求打印的语句只能输出到控制台 given().log ...
- sqlserver常用函数
1.字符串函数 --ascii函数,返回字符串最左侧字符的ascii码值 SELECT ASCII('dsd') AS asciistr --ascii代码转换函数,返回指定ascii值对应的字符 ) ...
- RabbitMq初探——消息分发
消息分发 前言 我们在用到消息队列的场景,一般是处理逻辑复杂,耗时,所以将同步改为异步处理,接入队列,下游处理耗时任务. 队列消息数量很大,且下游worker进程(消费者)处理耗时长,所以就有了任务的 ...
- django系列1--介绍与简单原理, wsgiref模块
一.web应用框架 Web应用框架(Web application framework)是一种计算机软件框架,用来支持动态网站.网络应用程序及网络服务的开发.这种框架有助于减轻网页开发时共通性活动的工 ...
- Python----初次见面,请多关照!
1.计算机的最基本认识 CPU(大脑) 3GHZ + 内存(DDR4) + 主板 + 电源(心脏)+ 显示器 + 键盘 +鼠标+ 显卡 + 硬盘 80MB/s 操作系统分为: windows 家用 l ...