java基于socket公共聊天室的实现
项目:一个公共聊天室功能的实现,实现了登录聊天,保存聊天记录等功能。
一、实现代码
1.客户端
ChatClient.java
import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketException; import java.util.Scanner; import java.util.StringTokenizer; public class ChatClient { // 创建一个Socket private static Socket client = null; // 定义输入流变量 private static DataInputStream di = null; // 定义输出流变量 private static DataOutputStream dos = null; // 创建scanner对象接收数据 Scanner sc = new Scanner(System.in); // 定义一个String变量保存用户名 static String name; // 定义一个布尔值来判断是否循环接受用户名 boolean falg = true; public static void main(String args[]) { // 创建对象 ChatClient cc = new ChatClient(); // 创建客户端的socket对象 client = new Socket(); // 调用方法 cc.connect(); // 调用方法 cc.send(); } // 连接 public void connect() { // 创建客户端的socket对象 client = new Socket(); // 定义一个String接收IP地址 String IP = null; // 定义一个int端口号 int port = 0; System.out.println("***!!Welcome!!***"); try { System.out.println("输入服务器的默认地址是0或127.0.0.1"); // 接收一个IP保存到string对象中 IP = sc.nextLine(); // 匹配接收到的IP,接收到后将IP赋值为默认 if (IP.equalsIgnoreCase("0")) { IP = ""; } // 设置端口号 port = 8000; } catch (Exception e) { } try { // 从给定的主机名得到ip存入inetaddress对象中 InetAddress address = InetAddress.getByName(IP); // 根据得到的ip和端口号创建套接字地址 InetSocketAddress socketaddress = new InetSocketAddress(address, port); // 将客户端的套接字链接到服务器 try { // 连接服务器与客户端 client.connect(socketaddress); // 判断是否有连接 if (client.isConnected()) { // 调用方法 runn(); } else { client.connect(socketaddress); // 调用方法 connect(); } } catch (SocketException e) { System.out.println("不能连接到服务器,请重新输入"); // 调用connect()重新连接 connect(); } } catch (Exception e) { System.out.println("不能连接到服务器,请重新输入"); // 调用connect()重新连接 connect(); } } public void runn() { try { // 定义read对象 ClientThread read = null; // 创建read对象 read = new ClientThread(); // 创建readdata线程对象 Thread readData = new Thread(read); // 封装一个DataInputStream对象得到输入流 di = new DataInputStream(client.getInputStream()); // 封装一个DataOutputStream对象得到输出流 dos = new DataOutputStream(client.getOutputStream()); // 接受用户名 while (falg) { System.out.println("请输入用户名:"); name = sc.next(); System.out.println(name + "上线了"); System.out.println("欢迎进入聊天室,需要帮助请输入/A"); dos.writeUTF(name); dos.flush(); read.setDataInputStream(di); // 启动线程 readData.start(); // 改变flag中断循环 falg = false; } } catch (IOException e) { } } // 写入信息 @SuppressWarnings("deprecation") public void send() { // 循环接收发送的消息 System.out.println("请输入内容:"); while (sc.hasNext()) { String mess; mess = sc.nextLine(); if (mess.equalsIgnoreCase("/0")) { System.exit(0); } else if (mess.equalsIgnoreCase("/D")) { try { File file = new File("qq.txt"); di = new DataInputStream(new FileInputStream(file)); String info = null; System.out.println("1 微笑;2 哭泣;3 疑问;4 加油;5 喔耶~;"); System.out.println("6 幸福;7 好冷;8 刺眼;9 昏倒;10 幸福;"); System.out.println("请选择表情:"); String age = sc.next(); while ((info = di.readLine()) != null) { StringTokenizer stri = new StringTokenizer(info, "."); String inn = stri.nextToken(); String in = stri.nextToken(); // System.out.println(in); if (age.equals(inn)) { dos.writeUTF(in); break; } } } catch (Exception e) { } } if (mess.equals("/D")) { System.out.println("请选择表情:"); } else { select(mess); } } } // 将消息发送给服务器 public void select(String mess) { // 判断输入的信息 if (mess.equalsIgnoreCase("/A")) { // 匹配上调用helpList()方法 helpList(); } else if (mess.equalsIgnoreCase("/C")) { try { System.out.println("请输入你要查看的聊天记录的名字"); String str1 = sc.next(); File file = new File(str1 + ".txt"); BufferedReader bf = new BufferedReader(new FileReader(file)); String str = null; while ((str = bf.readLine()) != null) { System.out.println(str); } bf.close(); } catch (IOException e) { } } else { try { // 将消息发送给服务器 dos.writeUTF(mess); // 清空输出流 dos.flush(); } catch (IOException e) { } } } public void helpList() { System.out.println("提示:进入聊天室,默认公聊!!"); System.out.println("/B 用户在线列表,用户/信息 私聊,/C 查看聊天记录,/D 发送表情,/0 退出系统"); } }
ClientThread.java
import java.io.BufferedWriter; import java.io.DataInputStream; import java.io.File; import java.io.FileWriter; import java.io.IOException; public class ClientThread implements Runnable { // 定义一个DataInputStream变量 DataInputStream di; // 定义一个string对象接收服务器发送的消息 String str; boolean ff=true; public void setDataInputStream(DataInputStream di) { this.di = di; } public void run() { while (true) { try { // 从流中读取信息 str = di.readUTF(); // 调用writeFile将信息写入文件中 writeFile(str); // 显示信息 System.out.println(str); } catch (IOException e) { // 服务器断开后客户端显示提示信息 System.out.println("服务断开~~~~~~~"); // 终止客户端 System.exit(0); } } } public void writeFile(String str2) { try { // 创建一个文件 File file = new File(ChatClient.name + ".txt"); FileWriter fw = new FileWriter(file, true); BufferedWriter bw = new BufferedWriter(fw); bw.write(str2); // 写入一个行分隔符 bw.newLine(); // 关闭缓冲流 bw.close(); // 关闭字符输出流 fw.close(); } catch (IOException e) { e.printStackTrace(); } } }
2.服务端
ChatServer.java
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class ChatServer { // 定义一个serversocket对象 private static ServerSocket server = null; // 定义一个socket对象 private static Socket client = null; // 定义一个变量用来保存客户端的用户名 private static String name; // 定义一个布尔值变量 private static boolean falg = true; // 定义输入流变量 private static DataInputStream di = null; // 定义输出流变量 private static DataOutputStream dos = null; public static void main(String args[]) { // 创建ServerThread对象 ServerThread st = new ServerThread(); while (true) { try { // 创建serversocket对象指定端口号为8000 server = new ServerSocket(8000); } catch (IOException e) { System.out.println("正在监听!!"); } try { System.out.println("等待客户端连接...."); // 将客户端的套接字与服务器的套接字连接起来 client = server.accept(); System.out.println("连接成功!!"); // 将服务器的输入流封装到DataInputStream中 di = new DataInputStream(client.getInputStream()); // 将服务器的输出流封装到DataInputStream中 dos = new DataOutputStream(client.getOutputStream()); // 从流中读取用户名 while (falg) { name = di.readUTF(); if (st.checkp(name)) { System.out.println("客户的地址:" + client.getInetAddress()+ "\t" + name + ":进入聊天室"); // 将falg变为false falg = false; } else { // 清空输出流 dos.flush(); } } } catch (IOException e) { System.out.println("正在等待客户端呼叫......"); } // 判断是否有客户端连接到服务器 if (client.isConnected()) { // 创建服务器端的收发信息线程对象 ServerThread sth = new ServerThread(client, name); Thread th = new Thread(sth); // 启动线程 th.start(); falg = true; } } } }
ServerThread.java
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.IOException; import java.net.Socket; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; import java.util.StringTokenizer; public class ServerThread implements Runnable { // 定义一个socket变量 Socket client = null; // 定义一个Datainputstream变量 DataInputStream di = null; // 定义一个Dataoutputstream变量 DataOutputStream dos = null; // 定义一个变量保存连接当前线程的用户名 String name = null; // 创建一个hashtable对象用来保存所有的为客户端开辟的线程对象 static Hashtable<String, ServerThread> clientlist = new Hashtable<String, ServerThread>(); public ServerThread() { } public ServerThread(Socket client, String name) { try { // 将传入的client赋值给成员变量的client this.client = client; // 将传入的name赋值给成员变量的name this.name = name; // 将服务器的输出流封装到DataInputStream中 di = new DataInputStream(client.getInputStream()); // 将服务器的输出流封装到DataOutputStream中 dos = new DataOutputStream(client.getOutputStream()); } catch (IOException e) { } } public void run() { try { // 添加当前对象到hashtable clientlist.put(name, this); // 发送新用户进入的消息给所有客户端 sendallClient(name + "进入聊天室"); while (true) { // 定义一个string对象接受从流中读取到的信息 String mess = di.readUTF(); // 创建一个stringtokenizer对象分析接收到的消息 StringTokenizer str = new StringTokenizer(name, "/"); // 判断截取到的信息有没分隔符 // 如果有分隔符则判断为私聊发送信息 if (str.countTokens() == 2) { // 得到要发送私聊信息用户的姓名 String nameid = str.nextToken(); // 得到要发送的私聊信息 String message = str.nextToken(); // 调用发sendclient送私聊信息 sendClient(nameid, message); // 没有分隔符或者有多个分隔符是信息默认为公聊发送 } else if (mess.equalsIgnoreCase("/B")) { // 匹配到调用getlist方法 getList(); // 判断信息是否与-change匹配 } else if (mess.equalsIgnoreCase("/0")) { System.out.println("name" + "退出聊天室"); break; } else if (str.countTokens() == 1 || str.countTokens() >= 3) { // 调用sendallclient发送公聊信息 sendallClient(name + "说:" + mess); } } client.close(); } catch (Exception e) { } finally { // 清除客户端信息 clientlist.remove(name); File file = new File(name + ".txt"); // 文件删除 file.delete(); // 有人退出时,给所有人发送退出信息 sendallClient(name + "退出聊天室"); System.out.println(getDate() + " " + name + "退出聊天室"); } } // 公聊 public void sendallClient(String mess) { // 获得clientlist中值得ServerThread放入枚举集合中 Enumeration<ServerThread> allclients = clientlist.elements(); // 遍历所有客户 while (allclients.hasMoreElements()) { // 枚举中还有元素是,返回此举的下一个元素 ServerThread st = (ServerThread) allclients.nextElement(); try { // 将信息写入流中 st.dos.writeUTF(getDate() + "\t" + mess); // 刷新流 st.dos.flush(); } catch (IOException e) { Thread th = new Thread(st); // 产生异常中断此线程 th.interrupt(); } } } // 私聊 public void sendClient(String name1, String mess) { ServerThread st = clientlist.get(name1); ServerThread st1 = clientlist.get(name); try { // 将要发送的信息保存到流中 st.dos.writeUTF(getDate() + "\t" + name + "对你说:\t" + mess); // 刷新流 st.dos.flush(); // 把信息发给原客户端 st1.dos.writeUTF(getDate() + "\t你对" + name1 + "说:\t" + mess); // 刷新流 st1.dos.flush(); } catch (IOException e) { System.out.println("你发送的信息有误,请重新发送!"); //sendClient(name1, mess); } } public boolean checkp(String str) { boolean flag = true; // 得到所有的用户名 Enumeration<String> checkname = clientlist.keys(); // 循环检查用户名 while (checkname.hasMoreElements()) { // 枚举中还有元素是,返回此举的下一个元素 String sn = (String) checkname.nextElement(); // 判断用户名是否重复,重复的话返回false if (str.equalsIgnoreCase(sn)) { // 返回false flag = false; // 判断用户名是否为空 } else if (str.equalsIgnoreCase("")) { // 返回false flag = false; } } return flag; } // 关闭服务器 public void guanBi() { if (!(client == null)) { try { client.close(); System.out.println("客户端退出此系统"); } catch (IOException e) { } } } // 显示用户在线 public void getList() { // 获得所有键的枚举 Enumeration<String> checkname = clientlist.keys(); // 通过用户名获得线程对象 ServerThread st = clientlist.get(name); try { // 写入信息 st.dos.writeUTF("在线用户列表"); // 写入用户在线人数 st.dos.writeUTF(clientlist.size() + ":人在线"); } catch (IOException e1) { e1.printStackTrace(); } // 便利枚举 while (checkname.hasMoreElements()) { // 枚举中还有元素是,返回此举的下一个元素 String sn = (String) checkname.nextElement(); try { // 将用户信息写入流中 st.dos.writeUTF("用户名称:" + sn); // 清空输出流 st.dos.flush(); } catch (IOException e) { e.printStackTrace(); } } } // 时间 public String getDate() { // 获得data对象 Date nowTime = new Date(); // 创建格式化参数 String pattern = "HH:mm:ss"; // 创建SimpleDateFormat对象 SimpleDateFormat sdf = new SimpleDateFormat(pattern); // 定义一个变量接收时间 String timePattern = sdf.format(nowTime); // 返回当前时间 return timePattern; } }
二、补充
1.制作.bat执行文件
创建client.bat和server.bat,编辑.bat文件为 java -jar client.jar 和 java -jar server.jar
java基于socket公共聊天室的实现的更多相关文章
- Android 基于Socket的聊天室(一)
Socket是TCP/IP协议上的一种通信,在通信的两端各建立一个Socket,从而在通信的两端之间形成网络虚拟链路.一旦建立了虚拟的网络链路,两端的程序就可以通过虚拟链路进行通信. Client A ...
- Android 基于Socket的聊天应用(二)
很久没写BLOG了,之前在写Android聊天室的时候答应过要写一个客户(好友)之间的聊天demo,Android 基于Socket的聊天室已经实现了通过Socket广播形式的通信功能. 以下是我写的 ...
- 使用socket.io打造公共聊天室
最近的计算机网络课上老师开始讲socket,tcp相关的知识,当时脑袋里就蹦出一个想法,那就是打造一个聊天室.实现方式也挺多的,常见的可以用C++或者Java进行socket编程来构建这么一个聊天室. ...
- Ext JS学习第十六天 事件机制event(一) DotNet进阶系列(持续更新) 第一节:.Net版基于WebSocket的聊天室样例 第十五节:深入理解async和await的作用及各种适用场景和用法 第十五节:深入理解async和await的作用及各种适用场景和用法 前端自动化准备和详细配置(NVM、NPM/CNPM、NodeJs、NRM、WebPack、Gulp/Grunt、G
code&monkey Ext JS学习第十六天 事件机制event(一) 此文用来记录学习笔记: 休息了好几天,从今天开始继续保持更新,鞭策自己学习 今天我们来说一说什么是事件,对于事件 ...
- Socket.IO聊天室~简单实用
小编心语:大家过完圣诞准备迎元旦吧~小编在这里预祝大家元旦快乐!!这一次要分享的东西小编也不是很懂啊,总之小编把它拿出来是觉地比较稀奇,而且程序也没有那么难,是一个比较简单的程序,大家可以多多试试~ ...
- Java网络编程案例---聊天室
网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来. java.net包中JavaSE的API包含有类和接口,它们提供低层次的通信细节.你可以直接使用这些类和接口,来专注于解决 ...
- 基于WebSocket实现聊天室(Node)
基于WebSocket实现聊天室(Node) WebSocket是基于TCP的长连接通信协议,服务端可以主动向前端传递数据,相比比AJAX轮询服务器,WebSocket采用监听的方式,减轻了服务器压力 ...
- Java 网络编程 -- 基于TCP 实现聊天室 群聊 私聊
分析: 聊天室需要多个客户端和一个服务端. 服务端负责转发消息. 客户端可以发送消息.接收消息. 消息分类: 群聊消息:发送除自己外所有人 私聊消息:只发送@的人 系统消息:根据情况分只发送个人和其他 ...
- Java Socket 多线程聊天室
本来这次作业我是想搞个图形界面的,然而现实情况是我把题意理解错了,于是乎失去了最初的兴致,还是把程序变成了功能正确但是“UI”不友好的console了,但是不管怎么样,前期的图形界面的开发还是很有收获 ...
随机推荐
- 关于GPL的一些知识
1.什么是GPL GPL许可协议(GNU General Public License):只要软件中包含有其他GPL协议的产品或代码,那么该软件就必须也采用GPL许可协议且开源及免费.具有以下特点: ...
- jsp中两种include的区别【转】
引用文章:http://www.ibm.com/developerworks/cn/java/j-jsp04293/ http://www.cnblogs.com/lazycoding/archive ...
- 关于.net Microsoft.Office.Interop.Word组建操作word的问题,如何控制word表格单元格内部段落的样式。
控制word表格单元格内部文字样式.我要将数据导出到word当中,对于word表格一个单元格中的一段文字,要设置不同的样式,比如第一行文字作为标题要居中,加粗,第二行为正常的正文. 代码如下 publ ...
- docker在ubuntu14.04下的安装笔记
本文主要是参考官网教程进行ubuntu14.04的安装. 下面是我的安装笔记. 笔记原件完整下载: 链接: https://pan.baidu.com/s/1dEPQ8mP 密码: gq2p
- HttpClient接口测试之会话保持
HttpClient接口测试之会话保持 HttpClient4.X自带会话保持功能,使用同一个HttpClient未关闭的连接即可保持登陆会话,如果多个HttpClient想要使用一个登陆会话 ...
- sql join用法学习
为了在两个或更多的表中获取结果,我们常常会用到join inner join(又叫join) out join包括left join,right join和full join(也就是left+righ ...
- EntityFrameWork 使用时碰到的小问题
EntityFrameWork 使用时碰到的小问题 1,在使用orm访问数据库的相目里,也要引用EntityFrameWork.dll,否则无法使用orm 否则,编译错误 错误 5 "Sys ...
- Sql Server中不常用的表运算符之PIVOT
PIVOT是SQL Server2005新添加的一个表运算符,作用在于将行转为列. 先来看看他的基本语法: 来自http://technet.microsoft.com/zh-cn/library/m ...
- 如何在cluster上跑R脚本
R 是一个比较不错但是有时候操蛋的语言,不错是因为用着爽的时候真的很爽,操蛋是因为这种爽不是什么时候都可以的,比如说在cluster上批处理跑R脚本. 当然说这话有些在上面跑过的各种不服气,你丫傻逼吧 ...
- CentOS7安装问题及解决方案记录
CentOS7系统已安装好: 一.我想要实现系统桌面化. 需要运行 yum 命令. 出现第一个error: 1.提示错误:can not find a valid baseurl 86_X64.... ...