IM即时通讯(三) 多客户端文本传输之聊天功能
来源:互联网 发布:王中磊和女星 知乎 编辑:程序博客网 时间:2024/05/22 01:41
主要内容:
多线程的应用读写分离思想服务器转发
服务器转发是什么呢?
可以假想服务器是一个大型的数据中心,按照一定的规则,将信息送到你想送去的地方。而且,这里的规则是由开发者自己定义的。
源码实例:
客户端
package me.mxzf;import java.io.IOException;import java.net.InetAddress;import java.net.Socket;import java.net.UnknownHostException;/** * * @Title: Client * @Dscription: 客户端 * @author Deleter * @date 2017年3月12日 下午2:29:00 * @version 1.0 */public class Client { public static void main(String[] args) throws UnknownHostException, IOException { // 创建Socket实例 Socket socket = new Socket(InetAddress.getLocalHost(), 1234); // 包装写 new ThreadWriter(socket).start(); // 包装读 new ThreadReader(socket).start(); }}
客户端读线程
package me.mxzf;import java.io.DataInputStream;import java.io.IOException;import java.net.Socket;/** * * @Title: ThreadReader * @Dscription: 读线程 * @author Deleter * @date 2017年3月12日 下午2:32:46 * @version 1.0 */public class ThreadReader extends Thread { private Socket socket; private DataInputStream dis; private String content; public ThreadReader(Socket socket) { this.socket = socket; } @Override public void run() { try { // 用DataInputStream包装socket的输入流 dis = new DataInputStream(this.socket.getInputStream()); while (true) { // 一直阻塞,直到有消息到来,进入循环体 while ((content = dis.readUTF()) != null) { // 打印接收到的消息 System.out.println(content); } } } catch (IOException e) { e.printStackTrace(); } }}
客户端写线程
package me.mxzf;import java.io.DataOutputStream;import java.io.IOException;import java.net.Socket;/** * * @Title: ThreadWriter * @Dscription: 写线程 * @author Deleter * @date 2017年3月12日 下午2:33:25 * @version 1.0 */public class ThreadWriter extends Thread { private Socket socket; private DataOutputStream dos; public ThreadWriter(Socket socket) { this.socket = socket; } @Override public void run() { try { // 用DataOutputStream包装socket的输出流 dos = new DataOutputStream(socket.getOutputStream()); while (true) { // 等待3后 Thread.sleep(3000); // 向服务器发送"Hello World!" dos.writeUTF("Client:Hello World!"); // 刷新缓冲区,防止粘包 dos.flush(); } } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } }}
服务器
package me.mxzf;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import java.util.HashSet;/** * * @Title: Server * @Dscription: 服务器 * @author Deleter * @date 2017年3月12日 下午2:28:09 * @version 1.0 */public class Server { // 创建静态的集合来存放"客户通道" public static HashSet<ServerThread> lists = new HashSet<>(); public static void main(String[] args) throws IOException { // 创建ServerSocket实例 ServerSocket server = new ServerSocket(1234); // 在循环的外部定义变量,节约内存空间 Socket socket; ServerThread serverThread; while (true) { // 阻塞直到有客户端接入 socket = server.accept(); // 包装Socket serverThread = new ServerThread(socket, lists); serverThread.start(); // 将当前接入的"客户通道"保存在集合中 lists.add(serverThread); } } /** * 服务器转发 * * 这种遍历的方式,效率极低,不介意使用 * * 但是为了初学者更好的理解,我还是用了这种方式 */ public void forword(String serverSocketName, String content) { try { // 遍历集合 for (ServerThread serverThread : lists) { // 如果该ServerThread的toString与即将发送的目的地名称一致时 if (serverThread.toString().equals(serverSocketName)) { // 获取该ServerThread的输出流,向其中写出信息 serverThread.getDataOutputStream().writeUTF(content); // 同时,刷新该缓冲区 serverThread.getDataOutputStream().flush(); } } } catch (IOException e) { e.printStackTrace(); } }}
服务器读写线程
package me.mxzf;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;import java.net.Socket;import java.util.HashSet;/** * * @Title: ServerThread * @Dscription: 服务器读写线程 * @author Deleter * @date 2017年3月12日 下午2:31:57 * @version 1.0 */public class ServerThread extends Thread { private Socket socket; private HashSet<ServerThread> list; private DataInputStream dis; private DataOutputStream dos; public ServerThread(Socket socket, HashSet<ServerThread> list) { this.socket = socket; this.list = list; } @Override public void run() { try { // 用DataInputStream包装socket的输入流 dis = new DataInputStream(socket.getInputStream()); // 用DataOutputStream包装socket的输出流 dos = new DataOutputStream(socket.getOutputStream()); // 定义局部变量 String content; while (true) { // 一直阻塞,直到有消息到来,进入循环体 while ((content = dis.readUTF()) != null) { // 打印接收到的消息 System.out.println(content); // 服务器反馈消息 dos.writeUTF("Server:ok"); // 刷新缓冲区,防止粘包 dos.flush(); } } } catch (IOException e) { e.printStackTrace(); } } /* * 重写toString方法 * * @see java.lang.Thread#toString() */ @Override public String toString() { return "ServerThread [socket=" + socket + "]"; } /* * 获取输出流 */ public DataOutputStream getDataOutputStream() { return dos; }}
注意
1、客户端先进行写操作(重要)2、必须先启动服务端
扩展学习
可以自行扩展,添加自定义的信息格式,或者加入Scanner输入流等等
1 0
- IM即时通讯(三) 多客户端文本传输之聊天功能
- IM即时通讯(五) 语音传输
- java Smack整合Openfire服务器实现IM即时通讯聊天功能
- java Smack整合Openfire服务器实现IM即时通讯聊天功能
- IM菜鸟学习之Socket聊天-客户端
- IM即时通信(二) 文本传输
- IM聊天进阶(三)IM>openfire>mina>mina搭建服务端和客户端 实现简单点对点聊天
- Android开发--IM聊天项目(三)
- java 开发IM即时通讯客户端 --安装SWT插件(一)
- iOS 之基于XMPP的iphone聊天客户端(三)
- 简单迭代服务器端/客户端:模仿飞Q聊天功能,实现IM通信
- IceWarp 即时通讯(IM)服务
- IceWarp 即时通讯(IM)服务
- 即时通讯(IM)面试题
- IM即时通讯(四) 文件传输
- 音视频、即时通讯、IM对传统聊天的影响
- 给即时通讯IM添加一个自动聊天机器人
- Android客户端基于XMPP的IM(openfire+asmack)的聊天工具之登录(三)
- spring中常用的注解介绍
- PHP实现分页
- 基于IRIS(鸢尾花)数据集使用sklearn的特征工程练习
- minikube在mac单机上部署kubernetes沙箱环境
- Solidworks 如何在曲面添加文字
- IM即时通讯(三) 多客户端文本传输之聊天功能
- 使用Openlayer利用GeoServer编辑要素到postGIS注意问题(WFS-T)
- mybatis学习三 多级结果映射
- day05
- c#猜数字小游戏
- Machine Learning Application
- Unity 小项目:模拟太阳系
- 华为oj初级 合法IP
- int abs(int number)函数有感: 求补码和通过补码求对应的整数 C++(增加:数字的二进制表示中1的个数)