基于websocket和java的多人聊天室

合集下载

用javaWebSocket做一个聊天室

用javaWebSocket做一个聊天室

⽤javaWebSocket做⼀个聊天室最近⼀个项⽬中,需要⽤到Java的websocket新特性,于是就学了⼀下,感觉这技术还挺好玩的,瞬间知道⽹页上⾯的那些在线客服是怎么做的了。

先看图:实现了多客户机进⾏实时通讯。

下⾯看代码项⽬结构图:很简单,就1个类,1个页⾯然后看具体代码先看后端代码package com.main;import java.io.IOException;import java.util.concurrent.CopyOnWriteArraySet;import javax.websocket.*;import javax.websocket.server.ServerEndpoint;/*** @ServerEndpoint 注解是⼀个类层次的注解,它的功能主要是将⽬前的类定义成⼀个websocket服务器端,* 注解的值将被⽤于监听⽤户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端*/@ServerEndpoint("/websocket")public class H5ServletServerSocket {// 静态变量,⽤来记录当前在线连接数。

应该把它设计成线程安全的。

private static int onlineCount = 0;// concurrent包的线程安全Set,⽤来存放每个客户端对应的MyWebSocket对象。

若要实现服务端与单⼀客户端通信的话,可以使⽤Map来存放,其中Key可以为⽤户标识 private static CopyOnWriteArraySet<H5ServletServerSocket> webSocketSet = new CopyOnWriteArraySet<H5ServletServerSocket>();// 与某个客户端的连接会话,需要通过它来给客户端发送数据private Session session;/*** 连接建⽴成功调⽤的⽅法** @param session* 可选的参数。

基于websocket的聊天系统设计与实现

基于websocket的聊天系统设计与实现

基于websocket的聊天系统设计与实现WebSocket是一种在Web浏览器和服务器之间进行全双工通信的通信协议。

它允许客户端和服务器之间实时地进行双向通信,而不需要客户端发起请求。

基于WebSocket的聊天系统是一个能够实现实时通信的应用程序,用户可以通过该应用程序在一个或多个聊天室中发送消息、接收消息,并与其他用户进行实时交流。

设计和实现一个基于WebSocket的聊天系统需要考虑以下几个方面:1. 前后端交互设计:前端通过WebSocket与后端建立连接,后端负责处理接收到的消息并转发给目标用户或聊天室。

前端需要实现用户注册、登录、发送消息、接收消息等功能。

后端需要实现身份验证、消息路由和转发等功能。

2. 用户认证和身份验证:聊天系统需要确保只有经过身份验证的用户才能进入聊天室。

可以使用JWT(JSON Web Token)或其他身份验证机制来验证用户的身份,并在每个WebSocket连接上进行验证。

3. 消息的发送和接收:用户可以通过界面输入消息并将其发送到聊天室或特定的用户。

接收消息时,前端应能够实时地接收到其他用户发送的消息,并将其显示在用户界面上。

后端需要将接收到的消息转发给相应的聊天室或用户。

4. 聊天室管理:聊天系统中可以有多个聊天室,用户可以选择进入或创建聊天室。

后端需要提供API,用于创建聊天室、查找聊天室、加入聊天室和离开聊天室等功能。

5. 消息存储和历史记录:可以考虑将用户发送的消息存储在数据库中,以便后续查询和展示历史记录。

后端需要设计相应的数据库表结构,并提供API用于存储和查询消息。

6. 安全性和性能优化:聊天系统需要考虑安全性,并采取必要的措施防止恶意攻击和数据泄露。

同时,为了提高系统的性能,可以使用消息队列或缓存技术来处理用户的消息请求。

基于以上需求,设计和实现一个基于WebSocket的聊天系统可以按如下步骤进行:1. 前端页面设计与开发:设计用户界面,包括用户注册、登录、聊天室列表、聊天室界面等。

java websocket案例

java websocket案例

Java WebSocket案例:聊天室应用背景WebSocket是一种在Web浏览器和服务器之间进行双向通信的技术标准。

相比传统的HTTP请求-响应模式,WebSocket允许服务器主动向客户端推送消息,实现了实时通信的能力。

在Java中,我们可以使用Java API for WebSocket(JSR 356)来开发WebSocket应用。

本案例将展示如何使用Java WebSocket API来构建一个简单的聊天室应用。

在这个聊天室中,多个用户可以同时加入并实时发送消息,所有用户都能看到其他用户发送的消息。

过程1. 创建WebSocket服务器首先,我们需要创建一个WebSocket服务器来处理客户端的连接和消息。

在Java 中,可以使用javax.websocket包中的注解和接口来实现WebSocket服务器。

import java.io.IOException;import java.util.Collections;import java.util.HashSet;import java.util.Set;import javax.websocket.OnClose;import javax.websocket.OnError;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import javax.websocket.Session;import javax.websocket.server.ServerEndpoint;@ServerEndpoint("/chat")public class ChatServer {private static Set<Session> sessions = Collections.synchronizedSet(new Has hSet<>());@OnOpenpublic void onOpen(Session session) {sessions.add(session);}@OnMessagepublic void onMessage(String message, Session session) throws IOException{for (Session s : sessions) {s.getBasicRemote().sendText(message);}}@OnClosepublic void onClose(Session session) {sessions.remove(session);}@OnErrorpublic void onError(Session session, Throwable error) {System.err.println("发生错误:" + error.getMessage());}}在上述代码中,我们使用@ServerEndpoint注解来指定WebSocket服务器的URL路径。

Java Socket实现多人聊天室

Java Socket实现多人聊天室

Java Socket实现多人聊天室---swing做UI标签:socket聊天javaexception服务器string2011-08-31 15:06 20679人阅读评论(25) 收藏举报分类:java(21)版权声明:本文为博主原创文章,未经博主允许不得转载。

今天翻硬盘的workspace发现一个Java Socket实现多人聊天室的源码,不记得是什么时候的事情了,貌似不是我写的。

但写得还不错,至少算个有模有样的聊天室工具。

我简单的修改了一下,拿出来跟大家分享一下,仅供参考。

界面是用swing写的,还不懒,简约大方。

有图有真相:正如上图所示,这个程序分为服务器端和客户端,说白了就是两个main class,用eclipse 直接运行之。

聊天室的设计思想是:在局域网下,利用socket进行连接通信,当服务器端启动的时候,利用Thread线程不停的等待客户端的链接;当有客户端开启连接的时候,服务器端通过IO流反馈“上线用户”信息给客户端,客户端也使用线程不停的接收服务器的信息,从而实现多人在线聊天功能。

程序中有三个类,分别Server.java(服务器端)、Client(客户端)、User.java(javabean)。

代码如下:Server.java(服务器端):[html]view plaincopy1.import java.awt.BorderLayout;2.import java.awt.Color;3.import java.awt.GridLayout;4.import java.awt.Toolkit;5.import java.awt.event.ActionEvent;6.import java.awt.event.ActionListener;7.import java.awt.event.WindowAdapter;8.import java.awt.event.WindowEvent;9.import java.io.BufferedReader;10.i mport java.io.IOException;11.i mport java.io.InputStreamReader;12.i mport java.io.PrintWriter;13.i mport .BindException;14.i mport .ServerSocket;15.i mport .Socket;16.i mport java.util.ArrayList;17.i mport java.util.StringTokenizer;18.19.i mport javax.swing.DefaultListModel;20.i mport javax.swing.JButton;21.i mport javax.swing.JFrame;22.i mport javax.swing.JLabel;23.i mport javax.swing.JList;24.i mport javax.swing.JOptionPane;25.i mport javax.swing.JPanel;26.i mport javax.swing.JScrollPane;27.i mport javax.swing.JSplitPane;28.i mport javax.swing.JTextArea;29.i mport javax.swing.JTextField;30.i mport javax.swing.border.TitledBorder;31.32.p ublic class Server {33.34. private JFrame frame;35. private JTextArea contentArea;36. private JTextField txt_message;37. private JTextField txt_max;38. private JTextField txt_port;39. private JButton btn_start;40. private JButton btn_stop;41. private JButton btn_send;42. private JPanel northPanel;43. private JPanel southPanel;44. private JScrollPane rightPanel;45. private JScrollPane leftPanel;46. private JSplitPane centerSplit;47. private JList userList;48. private DefaultListModel listModel;49.50. private ServerSocket serverSocket;51. private ServerThread serverThread;52. private ArrayList<ClientThread> clients;53.54. private boolean isStart = false;55.56. // 主方法,程序执行入口57. public static void main(String[] args) {58. new Server();59. }60.61. // 执行消息发送62. public void send() {63. if (!isStart) {64. JOptionPane.showMessageDialog(frame, "服务器还未启动,不能发送消息!", "错误",65. JOptionPane.ERROR_MESSAGE);66. return;67. }68. if (clients.size() == 0) {69. JOptionPane.showMessageDialog(frame, "没有用户在线,不能发送消息!", "错误",70. JOptionPane.ERROR_MESSAGE);71. return;72. }73. String message = txt_message.getText().trim();74. if (message == null || message.equals("")) {75. JOptionPane.showMessageDialog(frame, "消息不能为空!", "错误",76. JOptionPane.ERROR_MESSAGE);77. return;78. }79. sendServerMessage(message);// 群发服务器消息80. contentArea.append("服务器说:" + txt_message.getText() + "\r\n");81. txt_message.setText(null);82. }83.84. // 构造放法85. public Server() {86.frame = new JFrame("服务器");87. // 更改JFrame的图标:88. //frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Client.class.getResource("qq.png")));89. frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Server.class.getResource("qq.png")));90.contentArea = new JTextArea();91. contentArea.setEditable(false);92. contentArea.setForeground(Color.blue);93.txt_message = new JTextField();94.txt_max = new JTextField("30");95.txt_port = new JTextField("6666");96.btn_start = new JButton("启动");97.btn_stop = new JButton("停止");98.btn_send = new JButton("发送");99. btn_stop.setEnabled(false);100.listModel = new DefaultListModel();erList = new JList(listModel);102.103.southPanel = new JPanel(new BorderLayout()); 104. southPanel.setBorder(new TitledBorder("写消息")); 105. southPanel.add(txt_message, "Center");106. southPanel.add(btn_send, "East");107.leftPanel = new JScrollPane(userList);108. leftPanel.setBorder(new TitledBorder("在线用户"));109.110.rightPanel = new JScrollPane(contentArea);111. rightPanel.setBorder(new TitledBorder("消息显示区"));112.113.centerSplit = new JSplitPane(JSplitPane.HORIZONTAL _SPLIT, leftPanel,114. rightPanel);115. centerSplit.setDividerLocation(100);116.northPanel = new JPanel();117. northPanel.setLayout(new GridLayout(1, 6)); 118. northPanel.add(new JLabel("人数上限"));119. northPanel.add(txt_max);120. northPanel.add(new JLabel("端口"));121. northPanel.add(txt_port);122. northPanel.add(btn_start);123. northPanel.add(btn_stop);124. northPanel.setBorder(new TitledBorder("配置信息"));125.126. frame.setLayout(new BorderLayout());127. frame.add(northPanel, "North");128. frame.add(centerSplit, "Center");129. frame.add(southPanel, "South");130. frame.setSize(600, 400);131. //frame.setSize(Toolkit.getDefaultToolkit().getScr eenSize());//设置全屏132. int screen_width = Toolkit.getDefaultToolkit().get ScreenSize().width;133. int screen_height = Toolkit.getDefaultToolkit().ge tScreenSize().height;134. frame.setLocation((screen_width - frame.getWidth() ) / 2,135. (screen_height - frame.getHeight()) / 2);136. frame.setVisible(true);137.138. // 关闭窗口时事件139. frame.addWindowListener(new WindowAdapter() { 140. public void windowClosing(WindowEvent e) { 141. if (isStart) {142. closeServer();// 关闭服务器143. }144. System.exit(0);// 退出程序145. }146. });147.148. // 文本框按回车键时事件149. txt_message.addActionListener(new ActionListener() {150. public void actionPerformed(ActionEvent e) { 151. send();152. }153. });154.155. // 单击发送按钮时事件156. btn_send.addActionListener(new ActionListener() {157. public void actionPerformed(ActionEvent arg0) {158. send();159. }160. });161.162. // 单击启动服务器按钮时事件163. btn_start.addActionListener(new ActionListener() {164. public void actionPerformed(ActionEvent e) { 165. if (isStart) {166. JOptionPane.showMessageDialog(frame, "服务器已处于启动状态,不要重复启动!",167. "错误", JOptionPane.ERROR_MESSAGE);168. return;169. }170. int max;171. int port;172. try {173. try {174.max = Integer.parseInt(txt_max.get Text());175. } catch (Exception e1) {176. throw new Exception("人数上限为正整数!");177. }178. if (max <= 0) {179. throw new Exception("人数上限为正整数!");180. }181. try {182.port = Integer.parseInt(txt_port.g etText());183. } catch (Exception e1) {184. throw new Exception("端口号为正整数!");185. }186. if (port <= 0) {187. throw new Exception("端口号为正整数!");188. }189. serverStart(max, port);190. contentArea.append("服务器已成功启动!人数上限:" + max + ",端口:" + port191. + "\r\n");192. JOptionPane.showMessageDialog(frame, "服务器成功启动!");193. btn_start.setEnabled(false);194. txt_max.setEnabled(false);195. txt_port.setEnabled(false);196. btn_stop.setEnabled(true);197. } catch (Exception exc) {198. JOptionPane.showMessageDialog(frame, e xc.getMessage(),199. "错误", JOptionPane.ERROR_MESSAGE);200. }201. }202. });203.204. // 单击停止服务器按钮时事件205. btn_stop.addActionListener(new ActionListener() {206. public void actionPerformed(ActionEvent e) { 207. if (!isStart) {208. JOptionPane.showMessageDialog(frame, "服务器还未启动,无需停止!", "错误",209. JOptionPane.ERROR_MESSAGE); 210. return;211. }212. try {213. closeServer();214. btn_start.setEnabled(true);215. txt_max.setEnabled(true);216. txt_port.setEnabled(true);217. btn_stop.setEnabled(false);218. contentArea.append("服务器成功停止!\r\n");219. JOptionPane.showMessageDialog(frame, "服务器成功停止!");220. } catch (Exception exc) {221. JOptionPane.showMessageDialog(frame, "停止服务器发生异常!", "错误",222. JOptionPane.ERROR_MESSAGE); 223. }224. }225. });226. }227.228. // 启动服务器229. public void serverStart(int max, int port) throws java .net.BindException {230. try {231.clients = new ArrayList<ClientThread>();232.serverSocket = new ServerSocket(port); 233.serverThread = new ServerThread(serverSocket, max);234. serverThread.start();235.isStart = true;236. } catch (BindException e) {237.isStart = false;238. throw new BindException("端口号已被占用,请换一个!");239. } catch (Exception e1) {240. e1.printStackTrace();241.isStart = false;242. throw new BindException("启动服务器异常!"); 243. }244. }245.246. // 关闭服务器247. @SuppressWarnings("deprecation")248. public void closeServer() {249. try {250. if (serverThread != null)251. serverThread.stop();// 停止服务器线程252.253. for (int i = clients.size() - 1; i >= 0; i--) {254. // 给所有在线用户发送关闭命令255. clients.get(i).getWriter().println("CLOSE");256. clients.get(i).getWriter().flush(); 257. // 释放资源258. clients.get(i).stop();// 停止此条为客户端服务的线程259. clients.get(i).reader.close();260. clients.get(i).writer.close();261. clients.get(i).socket.close();262. clients.remove(i);263. }264. if (serverSocket != null) {265. serverSocket.close();// 关闭服务器端连接266. }267. listModel.removeAllElements();// 清空用户列表268.isStart = false;269. } catch (IOException e) {270. e.printStackTrace();271.isStart = true;272. }273. }274.275. // 群发服务器消息276. public void sendServerMessage(String message) { 277. for (int i = clients.size() - 1; i >= 0; i--) { 278. clients.get(i).getWriter().println("服务器:" + message + "(多人发送)");279. clients.get(i).getWriter().flush();280. }281. }282.283. // 服务器线程284. class ServerThread extends Thread {285. private ServerSocket serverSocket;286. private int max;// 人数上限287.288. // 服务器线程的构造方法289. public ServerThread(ServerSocket serverSocket, int max) {290.this.serverSocket = serverSocket;291.this.max = max;292. }293.294. public void run() {295. while (true) {// 不停的等待客户端的链接296. try {297. Socket socket = serverSocket.accept();298. if (clients.size() == max) {// 如果已达人数上限299. BufferedReader r = new BufferedRea der(300. new InputStreamReader(sock et.getInputStream()));301. PrintWriter w = new PrintWriter(so cket302. .getOutputStream()); 303. // 接收客户端的基本用户信息304. String inf = r.readLine();305. StringTokenizer st = new StringTok enizer(inf, "@");306. User user = new User(st.nextToken( ), st.nextToken());307. // 反馈连接成功信息308. w.println("MAX@服务器:对不起," + user.getName()309. + user.getIp() + ",服务器在线人数已达上限,请稍后尝试连接!");310. w.flush();311. // 释放资源312. r.close();313. w.close();314. socket.close();315. continue;316. }317. ClientThread client = new ClientThread (socket);318. client.start();// 开启对此客户端服务的线程319. clients.add(client);320. listModel.addElement(client.getUser().getName());// 更新在线列表321. contentArea.append(client.getUser().ge tName()322. + client.getUser().getIp() + "上线!\r\n");323. } catch (IOException e) {324. e.printStackTrace();325. }326. }327. }328. }329.330. // 为一个客户端服务的线程331. class ClientThread extends Thread {332. private Socket socket;333. private BufferedReader reader;334. private PrintWriter writer;335. private User user;336.337. public BufferedReader getReader() {338. return reader;339. }340.341. public PrintWriter getWriter() {342. return writer;343. }344.345. public User getUser() {346. return user;347. }348.349. // 客户端线程的构造方法350. public ClientThread(Socket socket) {351. try {352.this.socket = socket;353.reader = new BufferedReader(new InputStrea mReader(socket354. .getInputStream()));355.writer = new PrintWriter(socket.getOutputS tream());356. // 接收客户端的基本用户信息357. String inf = reader.readLine();358. StringTokenizer st = new StringTokenizer(i nf, "@");er = new User(st.nextToken(), st.nextTok en());360. // 反馈连接成功信息361. writer.println(user.getName() + user.getIp () + "与服务器连接成功!");362. writer.flush();363. // 反馈当前在线用户信息364. if (clients.size() > 0) {365. String temp = "";366. for (int i = clients.size() - 1; i >= 0; i--) {367. temp += (clients.get(i).getUser().getName() + "/" + clients368. .get(i).getUser().getIp())369. + "@";370. }371. writer.println("USERLIST@" + clients.s ize() + "@" + temp);372. writer.flush();373. }374. // 向所有在线用户发送该用户上线命令375. for (int i = clients.size() - 1; i >= 0; i --) {376. clients.get(i).getWriter().println( 377. "ADD@" + user.getName() + user .getIp());378. clients.get(i).getWriter().flush(); 379. }380. } catch (IOException e) {381. e.printStackTrace();382. }383. }384.385. @SuppressWarnings("deprecation")386. public void run() {// 不断接收客户端的消息,进行处理。

JAVA结合WebSocket实现简单客服聊天功能

JAVA结合WebSocket实现简单客服聊天功能

JAVA结合WebSocket实现简单客服聊天功能说明:该⽰例只简单的实现了客服聊天功能。

1、聊天记录没有保存到数据库中,⼀旦服务重启,消息记录将会没有,如果需要保存到数据库中,可以扩展2、页⾯样式⽤的⽹上模板,样式可以⾃⼰进⾏修改3、只能由⽤户主要发起会话,管理员⽆法主动进⾏对话4、页⾯之间跳转代码没有包含在⾥⾯,请⾃⼰书写,在管理员消息列表页中,需要把该咨询的⽤户ID带到客服回复页⾯中5、${websocket_url} 这个为项⽬的URL地址效果截图:客服回复页⾯(member_admin_chat.html)管理员消息列表页(member_admin_chat_list.html)⽤户咨询页⾯(member_chat.html)代码:页⾯所需要⽤到的基础样式、图⽚,下载链接:(这个只是⾃⼰⽹上下载的样式demo,可以根据⾃⼰的来)pom.xml <dependency><groupId>javax</groupId><artifactId>javaee-api</artifactId><version>8.0</version><scope>provided</scope></dependency>或者jar包javax.websocket-api-1.0.jar下载地址:配置类WebSocketConfig.javapackage com.config;import javax.websocket.Endpoint;import javax.websocket.server.ServerApplicationConfig;import javax.websocket.server.ServerEndpointConfig;import java.util.Set;public class WebSocketConfig implements ServerApplicationConfig {@Overridepublic Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> endpointClasses) { return null;}@Overridepublic Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned) {//在这⾥会把含有@ServerEndpoint注解的类扫描加载进来,可以在这⾥做过滤等操作return scanned;}}消息DTO类(使⽤了lombok,这⾥不在多做说明)ChatDTO.javapackage com.websocket.dto;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import lombok.experimental.Accessors;/*** @author 。

JavaSocket+多线程实现多人聊天室功能

JavaSocket+多线程实现多人聊天室功能

JavaSocket+多线程实现多⼈聊天室功能本⽂实例为⼤家分享了Java Socket+多线程实现多⼈聊天室的具体代码,供⼤家参考,具体内容如下思路简介分为客户端和服务器两个类,所有的客户端将聊的内容发送给服务器,服务器接受后,将每⼀条内容发送给每⼀个客户端,客户端再显⽰在终端上。

客户端设计客户端包含2个线程,1个⽤来接受服务器的信息,再显⽰,1个⽤来接收键盘的输⼊,发送给服务器。

import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import .Socket;import java.nio.charset.StandardCharsets;import java.util.Scanner;public class WeChatClient { //WeChat的客户端类private Socket client;private String name;private InputStream in;private OutputStream out;private MassageSenter massageSenter;private MassageGeter massageGeter;class MassageGeter extends Thread{ //⼀个⼦线程类,⽤于客户端接收消息MassageGeter() throws IOException{in = client.getInputStream();}@Overridepublic void run() {int len;byte[] bytes = new byte[1024];try {while ((len = in.read(bytes)) != -1) { //此函数是阻塞的System.out.println(new String(bytes,0,len, StandardCharsets.UTF_8));}}catch (IOException e){System.out.println(e.toString());}System.out.println("Connection interruption");}}class MassageSenter extends Thread{ //⼀个⼦线程类,⽤于发送消息给服务器MassageSenter() throws IOException{out = client.getOutputStream();}@Overridepublic void run() {Scanner scanner = new Scanner(System.in);try {while (scanner.hasNextLine()) { //此函数为阻塞的函数String massage = scanner.nextLine();out.write((name + " : " + massage).getBytes(StandardCharsets.UTF_8));if(massage.equals("//exit"))break;}}catch (IOException e){e.printStackTrace();}}}WeChatClient(String name, String host, int port) throws IOException {//初始化,实例化发送和接收2个线程 = name;client = new Socket(host,port);massageGeter = new MassageGeter();massageSenter = new MassageSenter();}void login() throws IOException{//登录时,先发送名字给服务器,在接收到服务器的正确回应之后,启动线程out.write(name.getBytes(StandardCharsets.UTF_8));byte[] bytes = new byte[1024];int len;len = in.read(bytes);String answer = new String(bytes,0,len, StandardCharsets.UTF_8);if(answer.equals("logined!")) {System.out.println("Welcome to WeChat! "+name);massageSenter.start();massageGeter.start();try {massageSenter.join();//join()的作⽤是等线程结束之后再继续执⾏主线程(main)massageGeter.join();}catch (InterruptedException e){System.err.println(e.toString());}}else{System.out.println("Server Wrong");}client.close();}public static void main(String[] args) throws IOException{//程序⼊⼝String host = "127.0.0.1";WeChatClient client = new WeChatClient("Uzi",host,7777);client.login();}}服务器设计服务器包含3个线程类,端⼝监听线程,客户端接收信息线程,发送信息线程。

基于JAVA的多人聊天室的系统设计

基于JAVA的多人聊天室的系统设计

一、系统设计
1、用户界面设计
1、用户界面设计
聊天室的用户界面设计应遵循简单、直观、易用的原则。在聊天室中,用户 可以通过文本、语音、文件传输等多种方式进行交流。因此,界面设计中应包括 聊天窗口、语音聊天窗口、文件传输窗口等功能。
2、代码实现和优化
2、代码实现和优化
聊天室的代码实现应采用模块化的设计思想,将不同的功能模块进行分离, 以便于维护和扩展。在代码优化方面,应采用多线程技术,提高系统的并发性能 和稳定性。同时,应注意代码的健壮性和安全性,防止恶意攻击和数据泄露。
三、技术选型
1、系统架构
1、系统架构
本系统采用C/S架构,由客户端和服务器端两部分组成。客户端负责用户界面 的展示和用户数据的发送,服务器端负责用户注册登录的验证、聊天记录的存储 和管理、以及语音和文件传输等功能。
2、开发工具与技术方案
2、开发工具与技术方案
本系统开发使用JAVA语言,采用Eclipse作为开发工具。在技术方案上,我 们采用了多线程技术实现并发处理,使用Socket进行网络通信,同时采用了 JavaFX和Swing等前端技术进行界面设计。
2、常见问题与解决方法
2、常见问题与解决方法
在测试过程中,我们遇到了一些问题,如网络延迟、掉线、卡顿等现象。针 对这些问题,我们采用了如下解决方法:采用心跳检测机制来检测掉线和卡顿现 象;通过缓存技术来减少网络传输次数;优化代码算法来提高程序响应速度。
3、系统维护与改进
3、系统维护与改进
为了保证系统的稳定性和安全性,我们需要对系统进行日常维护和升级。具 体工作包括:定期备份数据、更新安全补丁、优化系统性能等。同时,我们将持 续收集用户的反馈意见和建议,以便对系统进行改进和优化。

使用WebSocket实现即时通讯(一个群聊的聊天室)

使用WebSocket实现即时通讯(一个群聊的聊天室)

使⽤WebSocket实现即时通讯(⼀个群聊的聊天室)随着互联⽹的发展,传统的HTTP协议已经很难满⾜Web应⽤⽇益复杂的需求了。

近年来,随着HTML5的诞⽣,WebSocket协议被提出,它实现了浏览器与服务器的全双⼯通信,扩展了浏览器与服务端的通信功能,使服务端也能主动向客户端发送数据。

传统的HTTP协议是⽆状态的,每次请求(request)都要由客户端(如浏览器)主动发起,服务端进⾏处理后返回response结果,⽽服务端很难主动向客户端发送数据;这种客户端是主动⽅,服务端是被动⽅的传统Web模式对于信息变化不频繁的Web应⽤来说造成的⿇烦较⼩,⽽对于涉及实时信息的Web应⽤却带来了很⼤的不便,如带有即时通信、实时数据、订阅推送等功能的应⽤。

在WebSocket规范提出之前,开发⼈员若要实现这些实时性较强的功能,经常会使⽤折衷的解决⽅法:轮询(polling)和Comet技术。

其实后者本质上也是⼀种轮询,只不过有所改进。

轮询是最原始的实现实时Web应⽤的解决⽅案。

轮询技术要求客户端以设定的时间间隔周期性地向服务端发送请求,频繁地查询是否有新的数据改动。

明显地,这种⽅法会导致过多不必要的请求,浪费流量和服务器资源。

Comet技术⼜可以分为长轮询和流技术。

长轮询改进了上述的轮询技术,减⼩了⽆⽤的请求。

它会为某些数据设定过期时间,当数据过期后才会向服务端发送请求;这种机制适合数据的改动不是特别频繁的情况。

流技术通常是指客户端使⽤⼀个隐藏的窗⼝与服务端建⽴⼀个HTTP长连接,服务端会不断更新连接状态以保持HTTP长连接存活;这样的话,服务端就可以通过这条长连接主动将数据发送给客户端;流技术在⼤并发环境下,可能会考验到服务端的性能。

这两种技术都是基于请求-应答模式,都不算是真正意义上的实时技术;它们的每⼀次请求、应答,都浪费了⼀定流量在相同的头部信息上,并且开发复杂度也较⼤。

**伴随着HTML5推出的WebSocket,真正实现了Web的实时通信,使B/S模式具备了C/S模式的实时通信能⼒。

javasocket实现聊天室java实现多人聊天功能

javasocket实现聊天室java实现多人聊天功能

javasocket实现聊天室java实现多⼈聊天功能⽤java socket做⼀个聊天室,实现多⼈聊天的功能。

看了极客学院的视频后跟着敲的。

(1DAY)服务端:1. 先写服务端的类MyServerSocket,⾥⾯放⼀个监听线程,⼀启动就好2. 实现服务端监听类ServerListener.java,⽤accept来监听,⼀旦有客户端连上,⽣成新的socket,就新建个线程实例ChatSocket。

启动线程后就把线程交给ChatManager管理3. 在ChatSocket中实现从客户端读取内容,把读取到的内容发给集合内所有的客户端4. ChatManager⾥⾯⽤vector来管理socket线程实例ChatSocket,并实现发送信息给其他的客户端客户端:1. 新建⼀个继承JFrame的MainWindow.java类,主要实现聊天窗⼝的UI,以及事件响应。

2. 新建StartClient.java类,把MainWindow中⽣成MainWindow主⽅法部分代码拷贝过来,这样就能在主程序中把窗体执⾏出来了。

3. 新建ChatManager(需要单例化的类)管理socket,实现聊天的输⼊输出功能。

最后记得在1中新建窗⼝后,传⼀份frame 的引⽤到ChatManager中,才能实现ChatManager对界⾯的显⽰。

⼯程结构如图以下为代码服务端:1. 先写服务端的类MyServerSocket,⾥⾯放⼀个监听线程,⼀启动就好package com.starnet.testserversocket.main;public class MyServerSocket {public static void main(String[] args) {new ServerListener().start();}}2.实现服务端监听类ServerListener.java,⽤accept来监听,⼀旦有客户端连上,⽣成新的socket,就新建个线程实例ChatSocket。

swoole 案例

swoole 案例

Swoole案例:基于WebSocket的多人在线聊天室1. 案例背景随着互联网的发展和智能手机的普及,实时通信变得越来越重要。

传统的HTTP协议在实现实时通信时存在一些限制,而WebSocket协议则可以提供双向通信的能力,使得实时通信更加高效和稳定。

Swoole是一个基于PHP语言开发的协程网络通信引擎,提供了丰富的网络编程组件和工具,可以方便地实现高性能的网络应用。

在本案例中,我们将使用Swoole来构建一个基于WebSocket的多人在线聊天室,实现实时的多人聊天功能。

2. 案例过程2.1 环境准备在开始之前,需要确保已经安装了PHP和Swoole扩展。

可以通过以下命令来安装Swoole扩展:$ pecl install swoole2.2 服务器端代码首先,我们需要创建一个服务器端的PHP脚本,用于接收和处理客户端的连接和消息。

在这个案例中,我们使用Swoole的WebSocket服务器类来实现服务器端的功能。

<?php// 创建WebSocket服务器$server = new Swoole\WebSocket\Server("0.0.0.0", 9501);// 监听WebSocket连接事件$server->on('open', function (Swoole\WebSocket\Server $server, $request) { echo "New connection: {$request->fd}\n";});// 监听WebSocket消息事件$server->on('message', function (Swoole\WebSocket\Server $server, $frame) { echo "Received message: {$frame->data}\n";// 广播消息给所有客户端foreach ($server->connections as $fd) {$server->push($fd, $frame->data);}});// 监听WebSocket关闭事件$server->on('close', function ($server, $fd) {echo "Connection closed: {$fd}\n";});// 启动WebSocket服务器$server->start();上述代码中,我们创建了一个WebSocket服务器,并监听了open、message和close三个事件。

websocket room 的概念

websocket room 的概念

一、websocket room 是什么?websocket room 是指使用WebSocket 技术实现的一个房间概念,通过该房间可以实现多用户之间的实时通信和数据传输。

在实际应用中,websocket room 可以用于构建上线聊聊室、多人游戏、实时数据监测等场景。

二、websocket room 的优势1. 实时性:利用 WebSocket 技术,websocket room 可以实现实时的消息传输和数据更新,用户之间的交互几乎是即时的。

2. 流畅性:由于 WebSocket 是基于 TCP 协议的,所以在传输数据时具有较低的延迟和较高的吞吐量,保证了用户体验的流畅性。

3. 扩展性:websocket room 可以根据实际需求,灵活扩展房间的容量和功能,适应不同规模和类型的应用场景。

4. 灵活性:websocket room 可以根据需求创建多个房间,每个房间可以包含不同的用户裙体,并可以实现不同的交互目的。

三、websocket room 的实现原理1. 基于 WebSocket 技术:websocket room 是基于 WebSocket技术的,WebSocket 是一种全双工通信协议,可以实现持久连接和双向通信,所以非常适合实时通信场景。

2. 房间管理:websocket room 通过管理房间的方式实现多用户之间的通信,每个房间可以包含多个用户,用户可以向房间发送消息,也可以接收来自房间的消息。

3. 数据传输:websocket room 通过 WebSocket 连接实现数据的传输,用户在加入房间后,可以实时收发消息和数据,实现实时通信和交互。

四、如何实现一个 websocket room1. 创建 WebSocket 服务器:首先需要创建一个基于 WebSocket 协议的服务器,该服务器负责管理连接、房间和消息的传输。

2. 房间管理:在服务器端实现房间管理逻辑,包括创建、加入、离开房间等功能,保证多用户在同一个房间内可以进行实时通信。

多线程+socket实现多人聊天室

多线程+socket实现多人聊天室

多线程+socket实现多⼈聊天室最近在学习多线程的时候打算做⼀个简单的多线程socke聊天的程序,结果发现⽹上的代码都没有完整的实现功能,所以⾃⼰实现了⼀个demo:demo功能⼤致就是,有⼀个服务端负责信息转发,多个客户端发送消息,当⼀个客户端发送消息时,其他的客户端都可以接受到。

服务端:客户端:客户端代码:package com.cky.client;import java.io.IOException;import java.io.InputStream;import java.io.PrintWriter;import .Socket;import .UnknownHostException;import java.util.Scanner;public class Client {private PrintWriter out;//private BufferedReader br;private Scanner scan;private Boolean flag=true;private Socket s;private InputStream is;public Client() throws UnknownHostException, IOException {s=new Socket("127.0.0.1", 5001);is=s.getInputStream();}public static void main(String []args) throws UnknownHostException, IOException {Client client =new Client();client.startup();}public void startup() throws UnknownHostException, IOException {out = new PrintWriter(s.getOutputStream(), true);//开启⼀个线程监听服务端的消息Thread ct=new Thread(new Runnable() {@Overridepublic void run() {while(true) {if(!flag) break;try {receive();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}});ct.start();//主线程负责发送消息System.out.println("请输⼊你的⽤户名:");scan = new Scanner(System.in);String name=scan.nextLine();out.println(name);System.out.println(name+",欢迎进⼊聊天室,输⼊quit退出");while(flag) {String read=scan.nextLine();if(read.equalsIgnoreCase("quit")) {flag=false;}//System.out.println(read);out.println(read);}s.close();}public void receive() throws IOException {byte ss[]=new byte[1024];int length=s.getInputStream().read(ss);System.out.println(new String(ss,0,length));}}服务端代码:package com.cky.server;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import .ServerSocket;import .Socket;import java.util.ArrayList;import java.util.List;public class Server {private List<ThreadServer> clients=new ArrayList<ThreadServer>();public void startup() throws IOException {System.out.println("监听5001端⼝");ServerSocket ss=new ServerSocket(5001);while(true){Socket socket=ss.accept();System.out.println("发现新⽤户");Thread st=new Thread(new ThreadServer(socket));st.start();}}public class ThreadServer implements Runnable{private Socket socket;private BufferedReader br;private PrintWriter out;private String name;private Boolean flag=true;public ThreadServer(Socket socket) throws IOException {this.socket=socket;br=new BufferedReader(new InputStreamReader(socket.getInputStream())); out=new PrintWriter(socket.getOutputStream(),true);String str=br.readLine();name=str+"["+socket.getInetAddress().getHostAddress()+":"+socket.getPort()+"]"; System.out.println(name+"加⼊该聊天室");send(name+"加⼊该聊天室");clients.add(this);}private void send(String message) {for (ThreadServer threadServer : clients) {System.out.println("-->已向线程"++"发送消息");threadServer.out.print(message);threadServer.out.flush();}}private void receive() throws IOException {String message;while(flag=true) {message=br.readLine();if(message.equalsIgnoreCase("quit")) {System.out.println("⽤户"+name+"退出了");out.println("quit");out.flush();clients.remove(this);flag=false;}System.out.println(name+":"+message);send(name+":"+message);}}@Overridepublic void run() {try {while(flag=true) {receive();}} catch (IOException e) {e.printStackTrace();}finally {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}public static void main(String []args) throws IOException {Server server=new Server();System.out.println("服务器开启");server.startup();}}先启动服务端,监听端⼝,再使⽤客户端登录发送消息。

javaweb与websocket实现在线聊天功能总结

javaweb与websocket实现在线聊天功能总结

javaweb与websocket实现在线聊天功能总结技术从⼀开始ajax轮询后来改成websocket 碰到的⼀些问题的处理:websocket的pom依赖<dependency><groupId>org.springframework</groupId><artifactId>spring-websocket</artifactId><version>4.0.5.RELEASE</version></dependency>⾸先是配置处理器import javax.annotation.Resource;import ponent;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;import org.springframework.web.socket.config.annotation.EnableWebSocket;import org.springframework.web.socket.config.annotation.WebSocketConfigurer;import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;/*** WebScoket配置处理器* @author Goofy* @Date 2015年6⽉11⽇下午1:15:09*/@Component@EnableWebSocketpublic class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {@ResourceMyWebSocketHandler handler;public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(handler, "/ws").addInterceptors(new HandShake());registry.addHandler(handler, "/ws/sockjs").addInterceptors(new HandShake()).withSockJS();}}2.请求所经过的握⼿拦截器主要⽤来将ServerHttpRequest⾥的session的⽤户信息存放在attributes⾥到处理的handle中会⾃动存⼊websocketsession的attribute⾥import java.util.Map;import javax.servlet.http.HttpSession;import org.springframework.http.server.ServerHttpRequest;import org.springframework.http.server.ServerHttpResponse;import org.springframework.http.server.ServletServerHttpRequest;import org.springframework.web.socket.WebSocketHandler;import org.springframework.web.socket.server.HandshakeInterceptor;/*** Socket建⽴连接(握⼿)和断开** @author Goofy* @Date 2015年6⽉11⽇下午2:23:09*/public class HandShake implements HandshakeInterceptor {public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { System.out.println("Websocket:⽤户[ID:" + ((ServletServerHttpRequest) request).getServletRequest().getSession(false).getAttribute("uid") + "]已经建⽴连接");if (request instanceof ServletServerHttpRequest) {ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;HttpSession session = servletRequest.getServletRequest().getSession(false);// 标记⽤户Long uid = (Long) session.getAttribute("uid");if(uid!=null){attributes.put("uid", uid);}else{return false;}}return true;}public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {}}Socket处理器处理连接通信或错误关闭等import java.io.IOException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Map.Entry;import ponent;import org.springframework.web.socket.CloseStatus;import org.springframework.web.socket.TextMessage;import org.springframework.web.socket.WebSocketHandler;import org.springframework.web.socket.WebSocketMessage;import org.springframework.web.socket.WebSocketSession;import org.xdemo.example.websocket.entity.Message;import com.google.gson.Gson;import com.google.gson.GsonBuilder;/*** Socket处理器** @author Goofy* @Date 2015年6⽉11⽇下午1:19:50*/@Componentpublic class MyWebSocketHandler implements WebSocketHandler {public static final Map<Long, WebSocketSession> userSocketSessionMap;static {userSocketSessionMap = new HashMap<Long, WebSocketSession>();}/*** 建⽴连接后*/public void afterConnectionEstablished(WebSocketSession session)throws Exception {Long uid = (Long) session.getAttributes().get("uid");if (userSocketSessionMap.get(uid) == null) {userSocketSessionMap.put(uid, session);}}/*** 消息处理,在客户端通过Websocket API发送的消息会经过这⾥,然后进⾏相应的处理*/public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {if(message.getPayloadLength()==0)return;Message msg=new Gson().fromJson(message.getPayload().toString(),Message.class);msg.setDate(new Date());sendMessageToUser(msg.getTo(), new TextMessage(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson(msg))); }/*** 消息传输错误处理*/public void handleTransportError(WebSocketSession session,Throwable exception) throws Exception {if (session.isOpen()) {session.close();}Iterator<Entry<Long, WebSocketSession>> it = userSocketSessionMap.entrySet().iterator();// 移除Socket会话while (it.hasNext()) {Entry<Long, WebSocketSession> entry = it.next();if (entry.getValue().getId().equals(session.getId())) {userSocketSessionMap.remove(entry.getKey());System.out.println("Socket会话已经移除:⽤户ID" + entry.getKey());break;}}}/*** 关闭连接后*/public void afterConnectionClosed(WebSocketSession session,CloseStatus closeStatus) throws Exception {System.out.println("Websocket:" + session.getId() + "已经关闭");Iterator<Entry<Long, WebSocketSession>> it = userSocketSessionMap.entrySet().iterator();// 移除Socket会话if (entry.getValue().getId().equals(session.getId())) {userSocketSessionMap.remove(entry.getKey());System.out.println("Socket会话已经移除:⽤户ID" + entry.getKey());break;}}}public boolean supportsPartialMessages() {return false;}/*** 给所有在线⽤户发送消息** @param message* @throws IOException*/public void broadcast(final TextMessage message) throws IOException {Iterator<Entry<Long, WebSocketSession>> it = userSocketSessionMap.entrySet().iterator();// 多线程群发while (it.hasNext()) {final Entry<Long, WebSocketSession> entry = it.next();if (entry.getValue().isOpen()) {// entry.getValue().sendMessage(message);new Thread(new Runnable() {public void run() {try {if (entry.getValue().isOpen()) {entry.getValue().sendMessage(message);}} catch (IOException e) {e.printStackTrace();}}}).start();}}}/*** 给某个⽤户发送消息** @param userName* @param message* @throws IOException*/public void sendMessageToUser(Long uid, TextMessage message)throws IOException {WebSocketSession session = userSocketSessionMap.get(uid);if (session != null && session.isOpen()) {session.sendMessage(message);}}} 页⾯<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String path = request.getContextPath();String basePath = request.getServerName() + ":"+ request.getServerPort() + path + "/";String basePath2 = request.getScheme() + "://"+ request.getServerName() + ":" + request.getServerPort()+ path + "/";%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN""/TR/html4/strict.dtd"><html xmlns="/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title></title><script type="text/javascript" src="<%=basePath2%>resources/jquery.js"></script> <style>textarea {height: 300px;width: 100%;outline: none;}input[type=button] {float: right;margin: 5px;width: 50px;height: 35px;border: none;color: white;font-weight: bold;outline: none;}.clear {background: red;}.send {background: green;}.clear:active {background: yellow;}.send:active {background: yellow;}.msg {width: 100%;height: 25px;outline: none;}#content {border: 1px solid gray;width: 100%;height: 400px;overflow-y: scroll;}.from {background-color: green;width: 80%;border-radius: 10px;height: 30px;line-height: 30px;margin: 5px;float: left;color: white;padding: 5px;font-size: 22px;}.to {background-color: gray;width: 80%;border-radius: 10px;height: 30px;line-height: 30px;margin: 5px;float: right;color: white;padding: 5px;font-size: 22px;}.name {color: gray;font-size: 12px;}.tmsg_text {color: white;background-color: rgb(47, 47, 47); font-size: 18px;border-radius: 5px;padding: 2px;}.fmsg_text {color: white;background-color: rgb(66, 138, 140); font-size: 18px;border-radius: 5px;}.sfmsg_text {color: white;background-color: rgb(148, 16, 16);font-size: 18px;border-radius: 5px;padding: 2px;}.tmsg {clear: both;float: right;width: 80%;text-align: right;}.fmsg {clear: both;float: left;width: 80%;}</style><script>var path = '<%=basePath%>';var uid=${uid eq null?-1:uid};if(uid==-1){location.href="<%=basePath2%>";}var from=uid;var fromName='${name}';var to=uid==1?2:1;var websocket;if ('WebSocket' in window) {websocket = new WebSocket("ws://" + path + "/ws?uid="+uid);} else if ('MozWebSocket' in window) {websocket = new MozWebSocket("ws://" + path + "/ws"+uid);} else {websocket = new SockJS("http://" + path + "/ws/sockjs"+uid);}websocket.onopen = function(event) {console.log("WebSocket:已连接");console.log(event);};websocket.onmessage = function(event) {var data=JSON.parse(event.data);console.log("WebSocket:收到⼀条消息",data);var textCss=data.from==-1?"sfmsg_text":"fmsg_text";$("#content").append("<div class='fmsg'><label class='name'>"+data.fromName+" "+data.date+"</label><div class='"+textCss+"'>"+data.text+"</div></div>");scrollToBottom();};websocket.onerror = function(event) {console.log("WebSocket:发⽣错误 ");console.log(event);};websocket.onclose = function(event) {console.log("WebSocket:已关闭");console.log(event);}function sendMsg(){var v=$("#msg").val();if(v==""){return;}else{var data={};data["from"]=from;data["fromName"]=fromName;data["to"]=to;data["text"]=v;websocket.send(JSON.stringify(data));$("#content").append("<div class='tmsg'><label class='name'>我 "+new Date().Format("yyyy-MM-dd hh:mm:ss")+"</label><div class='tmsg_text'>"+data.text+"</div></div>"); scrollToBottom();$("#msg").val("");}}function scrollToBottom(){var div = document.getElementById('content');div.scrollTop = div.scrollHeight;}Date.prototype.Format = function (fmt) { //author: meizzvar o = {"M+": this.getMonth() + 1, //⽉份"d+": this.getDate(), //⽇"h+": this.getHours(), //⼩时"s+": this.getSeconds(), //秒"q+": Math.floor((this.getMonth() + 3) / 3), //季度"S": this.getMilliseconds() //毫秒};if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));for (var k in o)if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));return fmt;}function send(event){var code;if(window.event){code = window.event.keyCode; // IE}else{code = e.which; // Firefox}if(code==13){sendMsg();}}function clearAll(){$("#content").empty();}</script></head><body>欢迎:${ }<div id="content"></div><input type="text" placeholder="请输⼊要发送的信息" id="msg" class="msg" onkeydown="send(event)"><input type="button" value="发送" class="send" onclick="sendMsg()" ><input type="button" value="清空" class="clear" onclick="clearAll()"></body></html> 碰到的⼀些问题以及处理的想法1.之前在拦截器的请求⾥⾯得不到session 使⽤从页⾯传进来的get⽅式得到参数uid(后来也没改什么调试的时候发现可以得到session)2.客服防⽌多处登陆的处理:每次登陆获取loginusermap 如果没有该⽤户新增有就更新然后替换map到session中登陆拦截器校验登陆的⽤户的sessionid和map⾥的是否⼀致不⼀致说明被挤重新跳转loginUserMap.put(user.getFid(), sessionId);request.getSession().getServletContext().setAttribute("loginUserMap", loginUserMap);3.按钮嵌在右侧的⼯具栏点击固定只弹出⼀个聊天⽹页var op;op = window.open("${webRoot}customerChat.json","newWin1");op.focus();4.兼容ios(看了请求头⾥的sec-websocket-extensions不⼀致就想的馊主意改头结果可⽤)if(request.getHeaders().get("sec-websocket-extensions").contains("x-webkit-deflate-frame")){List<String> list = new ArrayList<String>();list.add("permessage-deflate");request.getHeaders().remove("sec-websocket-extensions");request.getHeaders().put("sec-websocket-extensions",list);}兼容nginxupstream {server 127.0.0.1:8080;}server {listen 80;server_name localhost;location / {proxy_pass /;proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_read_timeout 1000s;}}前端WebSocket 连接关闭(代码:1006) 还需配置proxy_read_timeout 1000s;哈哈第⼀次写博客有点菜鸡 websokcet部分也是从⽹上找的demo。

java websocket案例

java websocket案例

java websocket案例摘要:1.Java WebSocket 简介2.WebSocket 案例一:聊天室3.WebSocket 案例二:在线投票4.WebSocket 案例三:实时股票信息5.总结正文:1.Java WebSocket 简介Java WebSocket 是一种在单个TCP 连接上进行全双工通信的协议。

相较于HTTP,WebSocket 提供了更快的数据传输速度和更低的延迟,使得实时应用和交互成为可能。

在Java 中,我们可以通过使用WebSocket API 和相关的库来实现WebSocket 应用。

2.WebSocket 案例一:聊天室聊天室是一个经典的实时通信应用。

在这个案例中,我们可以使用Java WebSocket 实现一个简单的聊天室,让用户能够实时地发送和接收消息。

通过WebSocket,我们可以实现客户端与服务器之间的双向通信,让用户能够实时地看到其他人发送的消息。

3.WebSocket 案例二:在线投票在线投票是一个实时的数据收集和处理应用。

使用Java WebSocket,我们可以实现一个实时的在线投票系统。

在这个系统中,用户可以实时地投票并查看投票结果。

通过WebSocket,我们可以实时地更新投票数据,让用户能够看到实时的投票结果。

4.WebSocket 案例三:实时股票信息实时股票信息是一个需要快速响应的应用。

使用Java WebSocket,我们可以实现一个实时的股票信息展示系统。

在这个系统中,用户可以实时地查看股票的涨跌情况。

通过WebSocket,我们可以实时地更新股票数据,让用户能够看到实时的股票信息。

5.总结Java WebSocket 为实时应用和交互提供了强大的支持。

通过使用WebSocket,我们可以实现聊天室、在线投票和实时股票信息等应用,为用户提供更加丰富和实时的体验。

JavaWebSocket实现网络聊天室(群聊+私聊)

JavaWebSocket实现网络聊天室(群聊+私聊)

JavaWebSocket实现⽹络聊天室(群聊+私聊)1、简单说明谢谢博主的⽂章和项⽬,我是抱着学习的态度,若有理解错的地⽅,请指正。

2、项⽬内容项⽬的功能说明去原博主博客看吧,项⽬上改进的地⽅,我具体做以下说明。

(1)webSocket服务对于webSocket服务代码,我进⾏⼀部分的封装和优化,主要是消息内容的封装、⽤户信息封装。

页⾯显⽰⽤户的昵称,指定⽤户昵称进⾏消息发送。

ChatServer.javapackage q.webSocket;import er;import monDate;import net.sf.json.JSONObject;import org.apache.log4j.Logger;import javax.servlet.http.HttpSession;import javax.websocket.*;import javax.websocket.server.PathParam;import javax.websocket.server.ServerEndpoint;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;/*** @author ccq* @Description webSocket服务* @date 2017/12/16 17:31*/@ServerEndpoint(value="/chatServer/{userid}", configurator = HttpSessionConfigurator.class)public class ChatServer {private static Logger logger = Logger.getLogger(ChatServer.class);private static int onlineCount = 0; // 记录连接数⽬// Map<⽤户id,⽤户信息>private static Map<String, OnlineUser> onlineUserMap = new ConcurrentHashMap<String, OnlineUser>(); //在线⽤户/*** 连接成功调⽤的⽅法*/@OnOpenpublic void onOpen(@PathParam("userid") String userid , Session session, EndpointConfig config){("[ChatServer] connection : userid = " + userid + " , sessionId = " + session.getId());// 增加⽤户数量addOnlineCount();// 获取当前⽤户的sessionHttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());User user = (User) httpSession.getAttribute("user"); // 获得当前⽤户信息// 将当前⽤户存到在线⽤户列表中OnlineUser onlineUser = new OnlineUser(user.getUserid(),user.getNickname(),session);onlineUserMap.put(user.getUserid(),onlineUser);// 通知所有在线⽤户,当前⽤户上线String content = "[" + CommonDate.getTime24() + " : " + user.getNickname() + "加⼊聊天室,当前在线⼈数为 " + getOnlineCount() + "位" + "]";JSONObject msg = new JSONObject();msg.put("content",content);String message = Message.getMessage(msg.toString(),Message.NOTICE,onlineUserMap.values());Message.broadcast(message,onlineUserMap.values());}/*** 连接关闭⽅法*/@OnClosepublic void onClose(@PathParam("userid") String userid,Session session,CloseReason closeReason){("[ChatServer] close : userid = " + userid + " , sessionId = " + session.getId() +" , closeCode = " + closeReason.getCloseCode().getCode() + " , closeReason = " +closeReason.getReasonPhrase());// 减少当前⽤户subOnlienCount();// 移除的⽤户信息OnlineUser removeUser = onlineUserMap.remove(userid);onlineUserMap.remove(userid);// 通知所有在线⽤户,当前⽤户下线String content = "["+ CommonDate.getTime24() + " : " + removeUser.getNickname() + " 离开聊天室,当前在线⼈数为 " + getOnlineCount() + "位" + "]";JSONObject msg = new JSONObject();msg.put("content",content);if(onlineUserMap.size() > 0){String message = Message.getMessage(msg.toString(), Message.NOTICE, onlineUserMap.values());Message.broadcast(message,onlineUserMap.values());}else{("content : ["+ CommonDate.getTime24() + " : " + removeUser.getNickname() + " 离开聊天室,当前在线⼈数为 " + getOnlineCount() + "位" + "]"); }}/*** 接收客户端的message,判断是否有接收⼈⽽选择进⾏⼴播还是指定发送* @param data 客户端发来的消息*/@OnMessagepublic void onMessage(@PathParam("userid") String userid,String data){("[ChatServer] onMessage : userid = " + userid + " , data = " + data);JSONObject messageJson = JSONObject.fromObject(data);JSONObject message = messageJson.optJSONObject("message");String to = message.optString("to");String from = message.optString("from");// 将⽤户id转换为名称to = erIdCastNickName(to);OnlineUser fromUser = onlineUserMap.get(from);String sendMessage = Message.getContent(fromUser,to,message.optString("content"),message.optString("time"));String returnData = Message.getMessage(sendMessage, messageJson.optString("type"),null);if(to == null || to.equals("")){ // 进⾏⼴播Message.broadcast(returnData.toString(),onlineUserMap.values());}else{Message.singleSend(returnData.toString(), onlineUserMap.get(from)); // 发送给⾃⼰String[] useridList = message.optString("to").split(",");for(String id : useridList){if(!id.equals(from)){Message.singleSend(returnData.toString(), onlineUserMap.get(id)); // 分别发送给指定的⽤户}}}}/*** 发⽣错误* @param throwable*/@OnErrorpublic void onError(@PathParam("userid") String userid,Session session,Throwable throwable){("[ChatServer] close : userid = " + userid + " , sessionId = " + session.getId() +" , throwable = " + throwable.getMessage() );}public static int getOnlineCount() {return onlineCount;}public synchronized void addOnlineCount(){onlineCount++;}public synchronized void subOnlienCount(){onlineCount--;}/*** 将⽤户id转换为名称* @param userIds* @return*/private String userIdCastNickName(String userIds){String niceNames = "";if(userIds != null && !userIds.equals("")){String[] useridList = userIds.split(",");String toName = "";for (String id : useridList){toName = toName + onlineUserMap.get(id).getNickname() + ",";}niceNames = toName.substring(0,toName.length() - 1);}return niceNames;}}OnlineUser.javapublic class OnlineUser {private String userid;private String nickname;private Session session;} Message.javapackage q.webSocket;import net.sf.json.JSONArray;import net.sf.json.JSONObject;import mons.collections.CollectionUtils;import org.apache.log4j.Logger;import javax.websocket.Session;import java.io.IOException;import java.util.ArrayList;import java.util.Collection;import java.util.List;/*** @author ccq* @Description 消息类* @date 2017/12/16 19:08*/public class Message {private static Logger logger = Logger.getLogger(Message.class);/*** 消息类型*/public static String NOTICE = "notice"; //通知public static String MESSAGE = "message"; //消息/*** 组装信息返回给前台* @param message 交互信息* @param type 信息类型* @param userList 在线列表* @return** "massage" : {* "from" : "xxx",* "to" : "xxx",* "content" : "xxx",* "time" : "xxxx.xx.xx"* },* "type" : {notice|message},* "list" : {[xx],[xx],[xx]}*/public static String getMessage(String message,String type,Collection<OnlineUser> userList){JSONObject msg = new JSONObject();msg.put("message",message);msg.put("type", type);if(CollectionUtils.isNotEmpty(userList)){List<String> propertys = new ArrayList<String>();propertys.add("session");JSONArray userListArray = JSONArray.fromObject(userList,JsonConfigUtils.getJsonConfig(propertys)); msg.put("list", userListArray);}return msg.toString();}/*** 消息内容* @param fromUser* @param to* @param content* @param time* @return* {* "from" : "xxx",* "to" : "xxx",* "content" : "xxx",* "time" : "xxxx.xx.xx"* }*/public static String getContent(OnlineUser fromUser,String to,String content,String time){JSONObject contentJson = new JSONObject();// 转化为json串时去掉session,⽤户session不能被序列化List<String> propertys = new ArrayList<String>();propertys.add("session");contentJson.put("from",JSONObject.fromObject(fromUser,JsonConfigUtils.getJsonConfig(propertys)));contentJson.put("to",to);contentJson.put("content",content);contentJson.put("time",time);return contentJson.toString();}/*** ⼴播消息* @param message 消息* @param onlineUsers 在线⽤户*/public static void broadcast(String message,Collection<OnlineUser> onlineUsers){/***************************在线⽤户***************************/StringBuffer userStr = new StringBuffer();for(OnlineUser user : onlineUsers){userStr.append(user.getNickname() + ",");}userStr.deleteCharAt(userStr.length()-1);("[broadcast] message = " + message + ", onlineUsers = " + userStr.toString());/***************************在线⽤户***************************/for(OnlineUser user : onlineUsers){try {user.getSession().getBasicRemote().sendText(message);} catch (IOException e) {e.printStackTrace();("消息发送失败!" + e.getMessage());continue;}}}/*** 对特定⽤户发送消息* @param message* @param onlineUser*/public static void singleSend(String message, OnlineUser onlineUser){("[singleSend] message = " + message + ", toUser = " + onlineUser.getNickname());try {onlineUser.getSession().getBasicRemote().sendText(message);} catch (IOException e) {e.printStackTrace();("消息发送失败!" + e.getMessage());}}}(2)⽤户头像上传确实⽐较好⽤,贴⼀下主要代码@RequestMapping(value = "{userid}/upload", method = RequestMethod.POST,produces = "application/json; charset=utf-8")@ResponseBodypublic String updateUserPassword(@PathVariable("userid") String userid,String image,HttpServletRequest request){JSONObject responseJson = new JSONObject();String filePath = "I:\\IDEA2017-02\\img\\";String PicName= UUID.randomUUID().toString()+".png";String header ="data:image";String[] imageArr=image.split(",");if(imageArr[0].contains(header)) {//是img的// 去掉头部image=imageArr[1];// 修改图⽚BASE64Decoder decoder = new BASE64Decoder();try {byte[] decodedBytes = decoder.decodeBuffer(image); // 将字符串格式的image转为⼆进制流(biye[])的decodedBytesString imgFilePath = filePath + PicName; //指定图⽚要存放的位File targetFile = new File(filePath);if(!targetFile.exists()){targetFile.mkdirs();}FileOutputStream out = new FileOutputStream(imgFilePath);//新建⼀个⽂件输出器,并为它指定输出位置imgFilePathout.write(decodedBytes); //利⽤⽂件输出器将⼆进制格式decodedBytes输出out.close();// 修改图⽚User user = userService.getUserById(userid);user.setProfilehead(PicName);int flag = userService.updateUser(user);if(flag > 0){Log log = LogUtil.setLog(userid, CommonDate.getTime24(), WordDefined.LOG_TYPE_UPDATE,WordDefined.LOG_DETAIL_UPDATE_PROFILEHEAD, NetUtil.getIpAddress(request)); logService.insertLog(log);}else{responseJson.put("result","error");responseJson.put("msg","上传失败!");}} catch (IOException e) {e.printStackTrace();}}responseJson.put("result","ok");responseJson.put("msg","上传成功!");responseJson.put("fileUrl","/pic/" + PicName);return responseJson.toString();}3、改进的图⽚4、源码地址(2017-12-17晚更新)由于⼩弟刚学会使⽤github,所以现在才把修改的代码地址放出来。

基于java编写局域网多人聊天室

基于java编写局域网多人聊天室

基于java编写局域⽹多⼈聊天室由于需要制作⽹络计算机⽹络课程设计,并且不想搞⽹络布线或者局域⽹路由器配置等等这种完全搞不懂的东西,最后决定使⽤socket基于java编写⼀个局域⽹聊天室:关于socket以及⽹络编程的相关知识详见我另⼀篇⽂章:程序基于C/S结构,即客户端服务器模式。

服务器:默认ip为本机ip需要双⽅确定⼀个端⼝号可设置最⼤连接⼈数可启动与关闭界⾯显⽰在线⽤户⼈以及姓名(本机不在此显⽰)客户端:需要⼿动设置服务器ip地址(局域⽹)⼿动设置端⼝号输⼊姓名可连接可断开程序运⾏界⾯如下:服务器:客户端:具体代码我会在最后上传。

软件有很多不⾜,其中⽐如:没有与数据库有任何交集优化:可将所有⽤户存放在数据库中,以及将聊天记录也放⼊数据库中没有实现⼀对⼀聊天优化:需重新定义⼀对⼀聊天的⽅法还有许多不⾜的地⽅,⽇后有兴趣再回来慢慢研究下⾯为该程序三个代码:User.javapublic class User{/*** ⽤户信息类* ⽤于记录⽤户个⼈信息:姓名以及IP*/private String name;private String ip;public User(String name, String ip) { = name;this.ip = ip;}public String getName() {return name;}public void setName(String name) { = name;}public String getIp() {return ip;}public void setIp(String ip) {this.ip = ip;}}Server_more.javaimport java.awt.BorderLayout;import java.awt.Color;import java.awt.GridLayout;import java.awt.Toolkit;import java.awt.event.ActionEvent;import java.awt.event.WindowEvent;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import .BindException;import .ServerSocket;import .Socket;import java.util.ArrayList;import java.util.StringTokenizer;import javax.swing.DefaultListModel;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JList;import javax.swing.JOptionPane;import javax.swing.JPanel;import javax.swing.JScrollPane;import javax.swing.JSplitPane;import javax.swing.JTextArea;import javax.swing.JTextField;import javax.swing.border.TitledBorder;public class Server_more {private JFrame frame;private JTextArea contentArea; //⽂本域private JTextField txt_message; //⽤于显⽰⽂本信息private JTextField txt_max; //设置最⼤连接⼈数private JTextField txt_port; //设置端⼝号private JButton btn_start; //开始按钮private JButton btn_stop; //断开按钮private JButton btn_send; //发送按钮private JPanel northPanel; //北⽅⾯板private JPanel southPanel; //南⽅⾯板private JScrollPane rightPanel; //左边滚动条private JScrollPane leftPanel; //右边滚动条private JSplitPane centerSplit; //分割线private JList userList; //列表组件private DefaultListModel listModel;private ServerSocket serverSocket;private ServerThread serverThread;private ArrayList<ClientThread> clients;private boolean isStart = false;// 主⽅法,程序执⾏⼊⼝public static void main(String[] args) {new Server_more();}// 执⾏消息发送public void send() {if (!isStart) {JOptionPane.showMessageDialog(frame, "服务器还未启动,不能发送消息!", "错误", JOptionPane.ERROR_MESSAGE);return;}if (clients.size() == 0) {JOptionPane.showMessageDialog(frame, "没有⽤户在线,不能发送消息!", "错误", JOptionPane.ERROR_MESSAGE);return;}String message = txt_message.getText().trim();if (message == null || message.equals("")) {JOptionPane.showMessageDialog(frame, "消息不能为空!", "错误",JOptionPane.ERROR_MESSAGE);return;}sendServerMessage(message);// 群发服务器消息contentArea.append("服务器:" + txt_message.getText() + "\r\n");txt_message.setText(null);}// 构造放法public Server_more() {frame = new JFrame("服务器");// 更改JFrame的图标://frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Client.class.getResource("qq.png"))); //frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Server.class.getResource("qq.png"))); contentArea = new JTextArea();contentArea.setEditable(false);contentArea.setForeground(Color.blue);txt_message = new JTextField();txt_max = new JTextField("30");txt_port = new JTextField("6666");btn_start = new JButton("启动");btn_stop = new JButton("停⽌");btn_send = new JButton("发送");btn_stop.setEnabled(false);listModel = new DefaultListModel();userList = new JList(listModel);southPanel = new JPanel(new BorderLayout());southPanel.setBorder(new TitledBorder("写消息"));southPanel.add(txt_message, "Center");southPanel.add(btn_send, "East");leftPanel = new JScrollPane(userList);leftPanel.setBorder(new TitledBorder("在线⽤户"));rightPanel = new JScrollPane(contentArea);rightPanel.setBorder(new TitledBorder("消息显⽰区"));centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel,rightPanel);centerSplit.setDividerLocation(100);northPanel = new JPanel();northPanel.setLayout(new GridLayout(1, 6));northPanel.add(new JLabel("⼈数上限"));northPanel.add(txt_max);northPanel.add(new JLabel("端⼝"));northPanel.add(txt_port);northPanel.add(btn_start);northPanel.add(btn_stop);northPanel.setBorder(new TitledBorder("配置信息"));frame.setLayout(new BorderLayout());frame.add(northPanel, "North");frame.add(centerSplit, "Center");frame.add(southPanel, "South");frame.setSize(600, 400);//frame.setSize(Toolkit.getDefaultToolkit().getScreenSize());//设置全屏int screen_width = Toolkit.getDefaultToolkit().getScreenSize().width;int screen_height = Toolkit.getDefaultToolkit().getScreenSize().height;frame.setLocation((screen_width - frame.getWidth()) / 2,(screen_height - frame.getHeight()) / 2);frame.setVisible(true);// 关闭窗⼝时事件frame.addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e) {if (isStart) {closeServer();// 关闭服务器}System.exit(0);// 退出程序}});// ⽂本框按回车键时事件txt_message.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {send();}});// 单击发送按钮时事件btn_send.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent arg0) {send();});// 单击启动服务器按钮时事件btn_start.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {if (isStart) {JOptionPane.showMessageDialog(frame, "服务器已处于启动状态,不要重复启动!", "错误", JOptionPane.ERROR_MESSAGE);return;}int max;int port;try {try {max = Integer.parseInt(txt_max.getText());} catch (Exception e1) {throw new Exception("⼈数上限为正整数!");}if (max <= 0) {throw new Exception("⼈数上限为正整数!");}try {port = Integer.parseInt(txt_port.getText());} catch (Exception e1) {throw new Exception("端⼝号为正整数!");}if (port <= 0) {throw new Exception("端⼝号为正整数!");}serverStart(max, port);contentArea.append("服务器已成功启动!⼈数上限:" + max + ",端⼝:" + port+ "\r\n");JOptionPane.showMessageDialog(frame, "服务器成功启动!");btn_start.setEnabled(false);txt_max.setEnabled(false);txt_port.setEnabled(false);btn_stop.setEnabled(true);} catch (Exception exc) {JOptionPane.showMessageDialog(frame, exc.getMessage(),"错误", JOptionPane.ERROR_MESSAGE);}}});// 单击停⽌服务器按钮时事件btn_stop.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {if (!isStart) {JOptionPane.showMessageDialog(frame, "服务器还未启动,⽆需停⽌!", "错误",JOptionPane.ERROR_MESSAGE);return;}try {closeServer();btn_start.setEnabled(true);txt_max.setEnabled(true);txt_port.setEnabled(true);btn_stop.setEnabled(false);contentArea.append("服务器成功停⽌!\r\n");JOptionPane.showMessageDialog(frame, "服务器成功停⽌!");} catch (Exception exc) {JOptionPane.showMessageDialog(frame, "停⽌服务器发⽣异常!", "错误",JOptionPane.ERROR_MESSAGE);}}});}// 启动服务器public void serverStart(int max, int port) throws .BindException {try {clients = new ArrayList<ClientThread>();serverSocket = new ServerSocket(port);serverThread = new ServerThread(serverSocket, max);serverThread.start();} catch (BindException e) {isStart = false;throw new BindException("端⼝号已被占⽤,请换⼀个!");} catch (Exception e1) {e1.printStackTrace();isStart = false;throw new BindException("启动服务器异常!");}}// 关闭服务器@SuppressWarnings("deprecation")public void closeServer() {try {if (serverThread != null)serverThread.stop();// 停⽌服务器线程for (int i = clients.size() - 1; i >= 0; i--) {// 给所有在线⽤户发送关闭命令clients.get(i).getWriter().println("CLOSE");clients.get(i).getWriter().flush();// 释放资源clients.get(i).stop();// 停⽌此条为客户端服务的线程clients.get(i).reader.close();clients.get(i).writer.close();clients.get(i).socket.close();clients.remove(i);}if (serverSocket != null) {serverSocket.close();// 关闭服务器端连接}listModel.removeAllElements();// 清空⽤户列表isStart = false;} catch (IOException e) {e.printStackTrace();isStart = true;}}// 群发服务器消息public void sendServerMessage(String message) {for (int i = clients.size() - 1; i >= 0; i--) {clients.get(i).getWriter().println("服务器:" + message + "(多⼈发送)"); clients.get(i).getWriter().flush();}}// 服务器线程class ServerThread extends Thread {private ServerSocket serverSocket;private int max;// ⼈数上限// 服务器线程的构造⽅法public ServerThread(ServerSocket serverSocket, int max) {this.serverSocket = serverSocket;this.max = max;}public void run() {while (true) {// 不停的等待客户端的链接try {Socket socket = serverSocket.accept();if (clients.size() == max) {// 如果已达⼈数上限BufferedReader r = new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter w = new PrintWriter(socket.getOutputStream());// 接收客户端的基本⽤户信息String inf = r.readLine();StringTokenizer st = new StringTokenizer(inf, "@");User user = new User(st.nextToken(), st.nextToken());// 反馈连接成功信息w.println("MAX@服务器:对不起," + user.getName()+ user.getIp() + ",服务器在线⼈数已达上限,请稍后尝试连接!"); w.flush();w.close();socket.close();continue;}ClientThread client = new ClientThread(socket);client.start();// 开启对此客户端服务的线程clients.add(client);listModel.addElement(client.getUser().getName());// 更新在线列表 contentArea.append(client.getUser().getName()+ client.getUser().getIp() + "上线!\r\n");} catch (IOException e) {e.printStackTrace();}}}}// 为⼀个客户端服务的线程class ClientThread extends Thread {private Socket socket;private BufferedReader reader;private PrintWriter writer;private User user;public BufferedReader getReader() {return reader;}public PrintWriter getWriter() {return writer;}public User getUser() {return user;}// 客户端线程的构造⽅法public ClientThread(Socket socket) {try {this.socket = socket;reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));writer = new PrintWriter(socket.getOutputStream());// 接收客户端的基本⽤户信息String inf = reader.readLine();StringTokenizer st = new StringTokenizer(inf, "@");user = new User(st.nextToken(), st.nextToken());// 反馈连接成功信息writer.println(user.getName() + user.getIp() + "与服务器连接成功!"); writer.flush();// 反馈当前在线⽤户信息if (clients.size() > 0) {String temp = "";for (int i = clients.size() - 1; i >= 0; i--) {temp += (clients.get(i).getUser().getName() + "/" + clients.get(i).getUser().getIp())+ "@";}writer.println("USERLIST@" + clients.size() + "@" + temp);writer.flush();}// 向所有在线⽤户发送该⽤户上线命令for (int i = clients.size() - 1; i >= 0; i--) {clients.get(i).getWriter().println("ADD@" + user.getName() + user.getIp());clients.get(i).getWriter().flush();}} catch (IOException e) {e.printStackTrace();}}@SuppressWarnings("deprecation")public void run() {// 不断接收客户端的消息,进⾏处理。

JavaSocket实现多人聊天系统

JavaSocket实现多人聊天系统

JavaSocket实现多⼈聊天系统本⽂实例为⼤家分享了Java Socket实现多⼈聊天系统的具体代码,供⼤家参考,具体内容如下前⾔开发环境:Eclipse Java 2019-06注意:本项⽬只在单主机运⾏调试过,没试过在局域⽹和不同主机之间接发消息和⽂件(估计不⾏),有需要的⾃⾏查阅资料。

⼀、多⼈聊天系统1.1 客户端Login.java:登录界⾯// Login.javapackage exp5;import java.awt.*;import javax.swing.*;public class Login {JTextField textField = null;JPasswordField pwdField = null;ClientReadAndPrint.LoginListen listener=null;// 构造函数public Login() {init();}void init() {JFrame jf = new JFrame("登录");jf.setBounds(500, 250, 310, 210);jf.setResizable(false); // 设置是否缩放JPanel jp1 = new JPanel();JLabel headJLabel = new JLabel("登录界⾯");headJLabel.setFont(new Font(null, 0, 35)); // 设置⽂本的字体类型、样式和⼤⼩jp1.add(headJLabel);JPanel jp2 = new JPanel();JLabel nameJLabel = new JLabel("⽤户名:");textField = new JTextField(20);JLabel pwdJLabel = new JLabel("密码: ");pwdField = new JPasswordField(20);JButton loginButton = new JButton("登录");JButton registerButton = new JButton("注册"); // 没设置功能jp2.add(nameJLabel);jp2.add(textField);jp2.add(pwdJLabel);jp2.add(pwdField);jp2.add(loginButton);jp2.add(registerButton);JPanel jp = new JPanel(new BorderLayout()); // BorderLayout布局jp.add(jp1, BorderLayout.NORTH);jp.add(jp2, BorderLayout.CENTER);// 设置监控listener = new ClientReadAndPrint().new LoginListen(); // 新建监听类listener.setJTextField(textField); // 调⽤PoliceListen类的⽅法listener.setJPasswordField(pwdField);listener.setJFrame(jf);pwdField.addActionListener(listener); // 密码框添加监听loginButton.addActionListener(listener); // 按钮添加监听jf.add(jp);jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置关闭图标作⽤jf.setVisible(true); // 设置可见}}ChatView.java:登录成功后的个⼈聊天界⾯// ChatView.javapackage exp5;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.io.File;import javax.swing.*;import javax.swing.filechooser.FileNameExtensionFilter;public class ChatView {String userName; //由客户端登录时设置JTextField text;JTextArea textArea;ClientReadAndPrint.ChatViewListen listener;// 构造函数public ChatView(String userName) {erName = userName ;init();}// 初始化函数void init() {JFrame jf = new JFrame("客户端");jf.setBounds(500,200,400,330); //设置坐标和⼤⼩jf.setResizable(false); // 缩放为不能缩放JPanel jp = new JPanel();JLabel lable = new JLabel("⽤户:" + userName);textArea = new JTextArea("***************登录成功,欢迎来到多⼈聊天室!****************\n",12, 35);textArea.setEditable(false); // 设置为不可修改JScrollPane scroll = new JScrollPane(textArea); // 设置滚动⾯板(装⼊textArea)scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); // 显⽰垂直条jp.add(lable);jp.add(scroll);text = new JTextField(20);JButton button = new JButton("发送");JButton openFileBtn = new JButton("发送⽂件");jp.add(text);jp.add(button);jp.add(openFileBtn);// 设置“打开⽂件”监听openFileBtn.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {showFileOpenDialog(jf);}});// 设置“发送”监听listener = new ClientReadAndPrint().new ChatViewListen();listener.setJTextField(text); // 调⽤PoliceListen类的⽅法listener.setJTextArea(textArea);listener.setChatViewJf(jf);text.addActionListener(listener); // ⽂本框添加监听button.addActionListener(listener); // 按钮添加监听jf.add(jp);jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置右上⾓关闭图标的作⽤jf.setVisible(true); // 设置可见}// “打开⽂件”调⽤函数void showFileOpenDialog(JFrame parent) {// 创建⼀个默认的⽂件选择器JFileChooser fileChooser = new JFileChooser();// 设置默认显⽰的⽂件夹fileChooser.setCurrentDirectory(new File("C:/Users/Samven/Desktop"));// 添加可⽤的⽂件过滤器(FileNameExtensionFilter 的第⼀个参数是描述, 后⾯是需要过滤的⽂件扩展名)// fileChooser.addChoosableFileFilter(new FileNameExtensionFilter("(txt)", "txt"));// 设置默认使⽤的⽂件过滤器(FileNameExtensionFilter 的第⼀个参数是描述, 后⾯是需要过滤的⽂件扩展名可变参数) fileChooser.setFileFilter(new FileNameExtensionFilter("(txt)", "txt"));// 打开⽂件选择框(线程将被堵塞,知道选择框被关闭)int result = fileChooser.showOpenDialog(parent); // 对话框将会尽量显⽰在靠近 parent 的中⼼// 点击确定if(result == JFileChooser.APPROVE_OPTION) {// 获取路径File file = fileChooser.getSelectedFile();String path = file.getAbsolutePath();ClientFileThread.outFileToServer(path);}}}Client.java:客户端// Client.javapackage exp5;import .*;import javax.swing.*;import java.awt.event.*;import java.io.*;public class Client {// 主函数,新建登录窗⼝public static void main(String[] args) {new Login();}}/*** 负责客户端的读和写,以及登录和发送的监听* 之所以把登录和发送的监听放在这⾥,是因为要共享⼀些数据,⽐如mySocket,textArea*/class ClientReadAndPrint extends Thread{static Socket mySocket = null; // ⼀定要加上static,否则新建线程时会清空static JTextField textInput;static JTextArea textShow;static JFrame chatViewJFrame;static BufferedReader in = null;static PrintWriter out = null;static String userName;// ⽤于接收从服务端发送来的消息public void run() {try {in = new BufferedReader(new InputStreamReader(mySocket.getInputStream())); // 输⼊流while (true) {String str = in.readLine(); // 获取服务端发送的信息textShow.append(str + '\n'); // 添加进聊天客户端的⽂本区域textShow.setCaretPosition(textShow.getDocument().getLength()); // 设置滚动条在最下⾯}} catch (Exception e) {}}/**********************登录监听(内部类)**********************/class LoginListen implements ActionListener{JTextField textField;JPasswordField pwdField;JFrame loginJFrame; // 登录窗⼝本⾝ChatView chatView = null;public void setJTextField(JTextField textField) {this.textField = textField;}public void setJPasswordField(JPasswordField pwdField) {this.pwdField = pwdField;}public void setJFrame(JFrame jFrame) {this.loginJFrame = jFrame;}public void actionPerformed(ActionEvent event) {userName = textField.getText();String userPwd = String.valueOf(pwdField.getPassword()); // getPassword⽅法获得char数组if(userName.length() >= 1 && userPwd.equals("123")) { // 密码为123并且⽤户名长度⼤于等于1chatView = new ChatView(userName); // 新建聊天窗⼝,设置聊天窗⼝的⽤户名(静态)// 建⽴和服务器的联系try {InetAddress addr = InetAddress.getByName(null); // 获取主机地址mySocket = new Socket(addr,8081); // 客户端套接字loginJFrame.setVisible(false); // 隐藏登录窗⼝out = new PrintWriter(mySocket.getOutputStream()); // 输出流out.println("⽤户【" + userName + "】进⼊聊天室!"); // 发送⽤户名给服务器out.flush(); // 清空缓冲区out中的数据} catch (IOException e) {e.printStackTrace();}// 新建普通读写线程并启动ClientReadAndPrint readAndPrint = new ClientReadAndPrint();readAndPrint.start();// 新建⽂件读写线程并启动ClientFileThread fileThread = new ClientFileThread(userName, chatViewJFrame, out);fileThread.start();}else {JOptionPane.showMessageDialog(loginJFrame, "账号或密码错误,请重新输⼊!", "提⽰", JOptionPane.WARNING_MESSAGE); }}}/**********************聊天界⾯监听(内部类)**********************/class ChatViewListen implements ActionListener{public void setJTextField(JTextField text) {textInput = text; // 放在外部类,因为其它地⽅也要⽤到}public void setJTextArea(JTextArea textArea) {textShow = textArea; // 放在外部类,因为其它地⽅也要⽤到}public void setChatViewJf(JFrame jFrame) {chatViewJFrame = jFrame; // 放在外部类,因为其它地⽅也要⽤到// 设置关闭聊天界⾯的监听chatViewJFrame.addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e) {out.println("⽤户【" + userName + "】离开聊天室!");out.flush();System.exit(0);}});}// 监听执⾏函数public void actionPerformed(ActionEvent event) {try {String str = textInput.getText();// ⽂本框内容为空if("".equals(str)) {textInput.grabFocus(); // 设置焦点(可⾏)// 弹出消息对话框(警告消息)JOptionPane.showMessageDialog(chatViewJFrame, "输⼊为空,请重新输⼊!", "提⽰", JOptionPane.WARNING_MESSAGE); return;}out.println(userName + "说:" + str); // 输出给服务端out.flush(); // 清空缓冲区out中的数据textInput.setText(""); // 清空⽂本框textInput.grabFocus(); // 设置焦点(可⾏)// textInput.requestFocus(true); // 设置焦点(可⾏)} catch (Exception e) {}}}}ClientFileThread.java:⽂件传输功能(客户端)// ClientFileThread.javapackage exp5;import java.io.*;import .*;import javax.swing.*;public class ClientFileThread extends Thread{private Socket socket = null;private JFrame chatViewJFrame = null;static String userName = null;static PrintWriter out = null; // 普通消息的发送(Server.java传来的值)static DataInputStream fileIn = null;static DataOutputStream fileOut = null;static DataInputStream fileReader = null;static DataOutputStream fileWriter = null;public ClientFileThread(String userName, JFrame chatViewJFrame, PrintWriter out) {erName = userName;this.chatViewJFrame = chatViewJFrame;ClientFileThread.out = out;}// 客户端接收⽂件public void run() {try {InetAddress addr = InetAddress.getByName(null); // 获取主机地址socket = new Socket(addr, 8090); // 客户端套接字fileIn = new DataInputStream(socket.getInputStream()); // 输⼊流fileOut = new DataOutputStream(socket.getOutputStream()); // 输出流// 接收⽂件while(true) {String textName = fileIn.readUTF();long totleLength = fileIn.readLong();int result = JOptionPane.showConfirmDialog(chatViewJFrame, "是否接受?", "提⽰",JOptionPane.YES_NO_OPTION);int length = -1;byte[] buff = new byte[1024];long curLength = 0;// 提⽰框选择结果,0为确定,1位取消if(result == 0){// out.println("【" + userName + "选择了接收⽂件!】");// out.flush();File userFile = new File("C:\\Users\\Samven\\Desktop\\接受⽂件\\" + userName);if(!userFile.exists()) { // 新建当前⽤户的⽂件夹userFile.mkdir();}File file = new File("C:\\Users\\Samven\\Desktop\\接受⽂件\\" + userName + "\\"+ textName); fileWriter = new DataOutputStream(new FileOutputStream(file));while((length = fileIn.read(buff)) > 0) { // 把⽂件写进本地fileWriter.write(buff, 0, length);fileWriter.flush();curLength += length;// out.println("【接收进度:" + curLength/totleLength*100 + "%】");// out.flush();if(curLength == totleLength) { // 强制结束break;}}out.println("【" + userName + "接收了⽂件!】");out.flush();// 提⽰⽂件存放地址JOptionPane.showMessageDialog(chatViewJFrame, "⽂件存放地址:\n" +"C:\\Users\\Samven\\Desktop\\接受⽂件\\" +userName + "\\" + textName, "提⽰", RMATION_MESSAGE);}else { // 不接受⽂件while((length = fileIn.read(buff)) > 0) {curLength += length;if(curLength == totleLength) { // 强制结束break;}}}fileWriter.close();}} catch (Exception e) {}}// 客户端发送⽂件static void outFileToServer(String path) {try {File file = new File(path);fileReader = new DataInputStream(new FileInputStream(file));fileOut.writeUTF(file.getName()); // 发送⽂件名字fileOut.flush();fileOut.writeLong(file.length()); // 发送⽂件长度fileOut.flush();int length = -1;byte[] buff = new byte[1024];while ((length = fileReader.read(buff)) > 0) { // 发送内容fileOut.write(buff, 0, length);fileOut.flush();}out.println("【" + userName + "已成功发送⽂件!】");out.flush();} catch (Exception e) {}}}1.2 服务器端MultiChat.java:多⼈聊天系统界⾯(服务器端)// MultiChat.javapackage exp5;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;import javax.swing.*;public class MultiChat {JTextArea textArea;// ⽤于向⽂本区域添加信息void setTextArea(String str) {textArea.append(str+'\n');textArea.setCaretPosition(textArea.getDocument().getLength()); // 设置滚动条在最下⾯}// 构造函数public MultiChat() {init();}void init() {JFrame jf = new JFrame("服务器端");jf.setBounds(500,100,450,500); // 设置窗⼝坐标和⼤⼩jf.setResizable(false); // 设置为不可缩放JPanel jp = new JPanel(); // 新建容器JLabel lable = new JLabel("==欢迎来到多⼈聊天系统(服务器端)==");textArea = new JTextArea(23, 38); // 新建⽂本区域并设置长宽textArea.setEditable(false); // 设置为不可修改JScrollPane scroll = new JScrollPane(textArea); // 设置滚动⾯板(装⼊textArea)scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); // 显⽰垂直条 jp.add(lable);jp.add(scroll);jf.addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e) {System.exit(0);}});jf.add(jp);jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置关闭图标作⽤jf.setVisible(true); // 设置可见}}Server.java:服务器端// Server.javapackage exp5;import java.io.*;import .*;import java.util.*;public class Server{static ServerSocket server = null;static Socket socket = null;static List<Socket> list = new ArrayList<Socket>(); // 存储客户端public static void main(String[] args) {MultiChat multiChat = new MultiChat(); // 新建聊天系统界⾯try {// 在服务器端对客户端开启⽂件传输的线程ServerFileThread serverFileThread = new ServerFileThread();serverFileThread.start();server = new ServerSocket(8081); // 服务器端套接字(只能建⽴⼀次)// 等待连接并开启相应线程while (true) {socket = server.accept(); // 等待连接list.add(socket); // 添加当前客户端到列表// 在服务器端对客户端开启相应的线程ServerReadAndPrint readAndPrint = new ServerReadAndPrint(socket, multiChat);readAndPrint.start();}} catch (IOException e1) {e1.printStackTrace(); // 出现异常则打印出异常的位置}}}/*** 服务器端读写类线程* ⽤于服务器端读取客户端的信息,并把信息发送给所有客户端*/class ServerReadAndPrint extends Thread{Socket nowSocket = null;MultiChat multiChat = null;BufferedReader in =null;PrintWriter out = null;// 构造函数public ServerReadAndPrint(Socket s, MultiChat multiChat) {this.multiChat = multiChat; // 获取多⼈聊天系统界⾯this.nowSocket = s; // 获取当前客户端}public void run() {try {in = new BufferedReader(new InputStreamReader(nowSocket.getInputStream())); // 输⼊流// 获取客户端信息并把信息发送给所有客户端while (true) {String str = in.readLine();// 发送给所有客户端for(Socket socket: Server.list) {out = new PrintWriter(socket.getOutputStream()); // 对每个客户端新建相应的socket套接字 if(socket == nowSocket) { // 发送给当前客户端out.println("(你)" + str);}else { // 发送给其它客户端out.println(str);}out.flush(); // 清空out中的缓存}// 调⽤⾃定义函数输出到图形界⾯multiChat.setTextArea(str);}} catch (Exception e) {Server.list.remove(nowSocket); // 线程关闭,移除相应套接字}}}ServerFileThread.java:⽂件传输功能(服务器端)// ServerFileThread.javapackage exp5;import java.io.*;import .*;import java.util.ArrayList;import java.util.List;public class ServerFileThread extends Thread{ServerSocket server = null;Socket socket = null;static List<Socket> list = new ArrayList<Socket>(); // 存储客户端public void run() {try {server = new ServerSocket(8090);while(true) {socket = server.accept();list.add(socket);// 开启⽂件传输线程FileReadAndWrite fileReadAndWrite = new FileReadAndWrite(socket);fileReadAndWrite.start();}} catch (IOException e) {e.printStackTrace();}}}class FileReadAndWrite extends Thread {private Socket nowSocket = null;private DataInputStream input = null;private DataOutputStream output = null;public FileReadAndWrite(Socket socket) {this.nowSocket = socket;}public void run() {try {input = new DataInputStream(nowSocket.getInputStream()); // 输⼊流while (true) {// 获取⽂件名字和⽂件长度String textName = input.readUTF();long textLength = input.readLong();// 发送⽂件名字和⽂件长度给所有客户端for(Socket socket: ServerFileThread.list) {output = new DataOutputStream(socket.getOutputStream()); // 输出流if(socket != nowSocket) { // 发送给其它客户端output.writeUTF(textName);output.flush();output.writeLong(textLength);output.flush();}}// 发送⽂件内容int length = -1;long curLength = 0;byte[] buff = new byte[1024];while ((length = input.read(buff)) > 0) {curLength += length;for(Socket socket: ServerFileThread.list) {output = new DataOutputStream(socket.getOutputStream()); // 输出流 if(socket != nowSocket) { // 发送给其它客户端output.write(buff, 0, length);output.flush();}}if(curLength == textLength) { // 强制退出break;}}}} catch (Exception e) {ServerFileThread.list.remove(nowSocket); // 线程关闭,移除相应套接字 }}}⼆、运⾏效果2.1 初始化服务器端(先运⾏Server.java)登录界⾯(接着运⾏Client.java,运⾏⼀次⽣成⼀个登录界⾯)这⾥我还没有实现注册功能,登录的⽤户名随意(不为空即可),密码是123。

websocket多人聊天原理

websocket多人聊天原理

websocket多人聊天原理WebSocket是一种在Web应用程序中实现实时通信的协议。

它允许服务器主动向客户端推送数据,而不需要客户端发送请求。

这种实时通信的特性使得WebSocket成为多人聊天应用程序的理想选择。

在传统的Web应用中,客户端需要定期向服务器发送请求来获取最新的数据。

这种轮询方式虽然能够实现实时通信,但却会增加服务器的负载,并且在数据没有更新时也会浪费带宽和资源。

而WebSocket通过在客户端和服务器之间建立持久的连接,使得服务器可以直接向客户端发送数据,避免了不必要的请求和响应。

在多人聊天应用中,WebSocket的工作原理如下:首先,客户端向服务器发起WebSocket握手请求,请求中包含一些必要的头部信息,如协议版本和握手秘钥等。

服务器收到握手请求后进行验证,如果验证通过,服务器会返回一个握手响应,告知客户端握手成功。

握手成功后,客户端和服务器之间的连接就建立起来了。

一旦连接建立,客户端和服务器就可以通过WebSocket进行双向通信了。

客户端可以向服务器发送消息,服务器可以接收并处理这些消息。

同样地,服务器也可以向客户端推送消息,客户端可以接收并显示这些消息。

这样,多个客户端就可以实现实时地互相发送和接收消息,从而形成一个多人聊天的环境。

在实际的应用中,为了区分不同的用户和消息,通常会使用用户ID 和消息ID进行标识。

当用户发送消息时,客户端会将消息内容、发送时间、用户ID等信息发送给服务器。

服务器收到消息后会进行处理,然后将消息转发给所有在线的用户。

接收到消息的客户端会根据消息ID和用户ID进行判断,如果是自己发送的消息,则在消息列表中显示为自己发送的消息,如果是别人发送的消息,则在消息列表中显示为别人发送的消息。

为了提高用户体验和系统性能,多人聊天应用通常会使用一些额外的功能和技术。

例如,可以实现消息的实时显示,即当有新消息到达时,客户端会立即显示出来,而不需要手动刷新页面。

使用Socket、Java开发一个CS架构的多人聊天室

使用Socket、Java开发一个CS架构的多人聊天室

Flash 客户端发来的字符串,通过输出流(OutputStream)向 Flash 客户端写字符串: while (true) { // readLine() 方法也是阻塞式的,当客户端有消息发来就读取,否 则就一直等待 String msg = reader.readLine(); // 当客户端发送的字符串为 null 时,说明客户端已经关闭,此时退 出循环 if (msg == null) { System.out.println("客户端已离开"); break; } // 将读入的信息加工后再写回客户端 writer.writeUTF("写回客户端的" + msg); } 以上是ServerSocket 与 AS 3 Socket 通信的基本原理。在实际应 用中,会有多个客户端连接这个ServerSocket,因此要创建一个多线 程的 Socket 服务器。 下面简述一下多线程 Socket 服务器原理:当 socketServer.accept() 之后就需要实例化一个线程对象,在该对象 中持有 socketServer.accept() 返回的 Socket 对象,然后让线程 跑起来执行读写操作。如果再来一个客户端就再跑一个线程,同样执行 读写操作。同时,用一个 List 容器来管理这些对象。 最终服务器端的代码如下: import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import .ServerSocket; import .Socket; import java.util.ArrayList; import java.util.Iterator; import java.util.List;
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

最新基于websocket与java的多人聊天室实现架构html5+websocket+javaEE7+tomcat8JavaEE7 最新的websocket1.0 APITomcat8开始支持websocket1.0 API【Tomcat implements the Java WebSocket 1.0 API defined by JSR-356】在编写代码之前你要导入javaEE7的jar包以便使用websocket API,将此项目部署到tomcat8里面。

具体代码如下:Java端:ChatAnnotation类;使用的是注解的方式。

package websocket.chat;import java.io.IOException;import java.util.Set;import java.util.concurrent.CopyOnWriteArraySet;import java.util.concurrent.atomic.AtomicInteger;import javax.websocket.OnClose;import javax.websocket.OnError;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import javax.websocket.Session;import javax.websocket.server.ServerEndpoint;import org.apache.juli.logging.Log;import org.apache.juli.logging.LogFactory;import util.HTMLFilter;@ServerEndpoint(value = "/websocket/chat")public class ChatAnnotation {private static final Log log =LogFactory.getLog(ChatAnnotation.class);private static final String GUEST_PREFIX = "Guest";private static final AtomicInteger connectionIds = new AtomicInteger(0);private static final Set<ChatAnnotation> connections =new CopyOnWriteArraySet<>();private final String nickname;private Session session;public ChatAnnotation() {nickname = GUEST_PREFIX + connectionIds.getAndIncrement(); }@OnOpenpublic void start(Session session) {this.session = session;connections.add(this);String message = String.format("* %s %s", nickname, "has joined.");broadcast(message);}@OnClosepublic void end() {connections.remove(this);String message = String.format("* %s %s",nickname, "has disconnected.");broadcast(message);}@OnMessagepublic void incoming(String message) {// Never trust the clientString filteredMessage = String.format("%s: %s",nickname, HTMLFilter.filter(message.toString()));broadcast(filteredMessage);}@OnErrorpublic void onError(Throwable t) throws Throwable {log.error("Chat Error: " + t.toString(), t);}private static void broadcast(String msg) {for (ChatAnnotation client : connections) {try {synchronized (client) {client.session.getBasicRemote().sendText(msg);}} catch (IOException e) {log.debug("Chat Error: Failed to send message to client", e);connections.remove(client);try {client.session.close();} catch (IOException e1) {// Ignore}String message = String.format("* %s %s",client.nickname, "has been disconnected."); broadcast(message);}}}}里面的juli.jar包可以百度一下自行下载。

util.HTMLFilter类如下:HTMLFilter类。

package util;/*** HTML filter utility.** @author Craig R. McClanahan* @author Tim Tye*/public final class HTMLFilter {/*** Filter the specified message string for characters that are sensitive* in HTML. This avoids potential attacks caused by including JavaScript* codes in the request URL that is often reported in error messages. ** @param message The message string to be filtered*/public static String filter(String message) {if (message == null)return (null);char content[] = new char[message.length()];message.getChars(0, message.length(), content, 0);StringBuilder result = new StringBuilder(content.length + 50); for (int i = 0; i < content.length; i++) {switch (content[i]) {case '<':result.append("&lt;");break;case '>':result.append("&gt;");break;case '&':result.append("&amp;");break;case '"':result.append("&quot;");break;default:result.append(content[i]);}}return (result.toString());}}接下来是web端:Chat.xhtml<?xml version="1.0" encoding="UTF-8"?><html xmlns="/1999/xhtml" xml:lang="en"><head><title>Apache Tomcat WebSocket Examples: Chat</title><style type="text/css"><![CDATA[input#chat {width: 410px}#console-container {width: 400px;}#console {border: 1px solid #CCCCCC;border-right-color: #999999;border-bottom-color: #999999;height: 170px;overflow-y: scroll;padding: 5px;width: 100%;}#console p {padding: 0;margin: 0;}]]></style><script type="application/javascript"><![CDATA["use strict";var Chat = {};Chat.socket = null;Chat.connect = (function(host) {if ('WebSocket' in window) {Chat.socket = new WebSocket(host);} else if ('MozWebSocket' in window) {Chat.socket = new MozWebSocket(host);} else {Console.log('Error: WebSocket is not supported by this browser.');return;}Chat.socket.onopen = function () {Console.log('Info: WebSocket connection opened.');document.getElementById('chat').onkeydown =function(event) {if (event.keyCode == 13) {Chat.sendMessage();}};};Chat.socket.onclose = function () {document.getElementById('chat').onkeydown = null; Console.log('Info: WebSocket closed.');};Chat.socket.onmessage = function (message) {Console.log(message.data);};});Chat.initialize = function() {if (window.location.protocol == 'http:') {Chat.connect('ws://' + window.location.host +'/examples/websocket/chat');} else {Chat.connect('wss://' + window.location.host +'/examples/websocket/chat');}};Chat.sendMessage = (function() {var message = document.getElementById('chat').value; if (message != '') {Chat.socket.send(message);document.getElementById('chat').value = '';}});var Console = {};Console.log = (function(message) {var console = document.getElementById('console');var p = document.createElement('p');p.style.wordWrap = 'break-word';p.innerHTML = message;console.appendChild(p);while (console.childNodes.length > 25) {console.removeChild(console.firstChild);}console.scrollTop = console.scrollHeight;});Chat.initialize();document.addEventListener("DOMContentLoaded", function() {// Remove elements with "noscript" class - <noscript> is not allowed in XHTMLvar noscripts =document.getElementsByClassName("noscript");for (var i = 0; i < noscripts.length; i++) {noscripts[i].parentNode.removeChild(noscripts[i]);}}, false);]]></script></head><body><div class="noscript"><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enableJavascript and reload this page!</h2></div><div><p><input type="text" placeholder="type and press enter to chat" id="chat" /></p><div id="console-container"><div id="console"/></div></div></body></html>亲自测试:如果按照以上步骤部署项目,保证能顺利运行。

相关文档
最新文档