首先实现的功能:

1.群聊。一个服务器端可以承载多个客户端(用户)来请求访问。服务器端对其请求做出处理,并转发给其他的客户端(用户)。

2.私聊。因为是控制台输入输出,所以私聊格式为:@xxx:   。而且自己给私发服务器端不响应。

思路:1.用ServerSocket模拟服务器端,并且开启多线程的调用accept()等待客户端连接。

2.Socket模拟客户端。使用多线程达到一边发一边收。

3.数据的传输用到的IO流DataInputStream(client.getInputStream())和DataOutputStream(client.getOutputStream())

4.TCP底层原理不再阐述。不懂:https://blog.csdn.net/qq_40301026/article/details/88623353

5.群聊功能:每来一个客户端,将其姓名作为key,客户端的对象地址作为value,,存在ConcurrentHashMap(线程安全)容器里面。当一个客户端发送消息时,服务器端作为中转站,从容器中拿到其他客户端,转发此消息。

6.私聊:对接收到的客户端消息进行检查,如果符合私聊格式就从容器中拿到私聊对象,转发给对方。

先来看看实现的效果????

*启动一个服务器端(IP地址本机,端口号:8848)和三个客户端。

*三个客户端加入聊天室

* 群聊

*私聊:

*离开:

代码:

服务器端:

package cn.liu.chat03;import java.io.IOException;
import java.net.ServerSocket;
import java.util.concurrent.ConcurrentHashMap;/*** 服务器端:利用多线程和多个客户端能收发多条消息* 再进行封装* 实现群聊功能* @author Administrator**/
public class Server {private ConcurrentHashMap<String,Work> holder;//用来存储客户端private ServerSocket server;//服务器端private int serverPort;//服务器的端口号//启动一个服务端public Server(int serverPort) {super();this.serverPort = serverPort;this.holder = new ConcurrentHashMap<>();//创建容器try {this.server = new ServerSocket(serverPort);//创建一个服务器端} catch (IOException e) {e.printStackTrace();}}//服务端响应,工作。public void run() {System.out.println("----------ChatServer----------");//响应多个客户端while(true) { new Thread(new Work(server,holder)).start();}}
}
package cn.liu.chat03;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;/*** //将服务器响应一个客户端的功能进行封装* * @author Administrator**/
public class Work implements Runnable{private Socket client;//拿到客户端套接字private ServerSocket server;//服务器端private DataInputStream is;//IO流通道private DataOutputStream os;//IO流通道private boolean flg;//控制多次收发private ConcurrentHashMap<String,Work> holder;//用来存储客户端private boolean sign ;//true是客户端消息,false是服务器消息//初始化,1.等待连接。2.并且将输入输出流通道搭建好public Work(ServerSocket server,ConcurrentHashMap<String,Work> holder) {super();try {this.client = server.accept();//将输入输出流通道搭建好this.is = new DataInputStream(client.getInputStream());this.os = new DataOutputStream(client.getOutputStream());} catch (IOException e) {e.printStackTrace();}this.holder = holder;this.flg = true;this.sign = true;}//执行的线程体@Overridepublic void run() {System.out.println("一个客户端已建立连接。");String name = judge();//得到此客户端名字judgeFirst(name);//当关闭此客户端,程序跳出judgeFirst()中while循环,服务器给其他客户端发送离开消息responseOther(name+":离开聊天室!");release();//释放相关资源}//判断客户端和其他客户端是不是重名,不重名则返回,并加入容器, 重名则重新接收。private String judge() {response("欢迎到来!");response("起一个好听的昵称吧!");while(true){String name = receive();if(!holder.containsKey(name)) {holder.put(name,this);//加入此客户端存起来return name;}else {String unname = "姓名重名了!请重新起一个!";response(unname);}}}//判断客户端是不是第一次发送消息,是则发送欢迎,不是则进行聊天功能(私聊OR群聊)。private void judgeFirst(String name) {while(flg) {if(sign) {//第一次给其他客户端转发此消息responseOther("欢迎"+name+"加入群聊!");sign = false;}else {String str = this.receive();if(str.equals(""))//关闭客户端,receive()收到"",则退出聊天室{break;}else {survey(name,str);}}}}//群聊private void groupChat(String name,String message) {String datas = name+":"+message;responseOther(datas);}//私聊,系统默认识别:“@xxx:”为私聊,之后的话为私发内容private void privateChat(String name,String str) {//对数据进行分离int index = 0;while(str.charAt(index)!=':') {index++;}String nameOther = str.substring(1,index);//得到名字str = name+str.substring(index);//处理信息//向此人转发信息for(ConcurrentHashMap.Entry<String,Work> entry: holder.entrySet()) {if(!entry.getValue().equals(this)) {//排除和自己私聊if(entry.getKey().equals(nameOther)) {//找到此客户端entry.getValue().response(str);//服务器转发此消息}}}}//检测是群聊还是私聊,检测后并调用相应功能private void survey(String name,String messager) {//有@即视为想私聊if(messager.charAt(0)=='@') {privateChat(name,messager);}else {groupChat(name,messager);}}//拿到客户数据private String receive() {//拿到客户端数据String str = "";try {str = is.readUTF();} catch (IOException e) {release();}return str;}//给客户端做出响应private void response(String str) {//m表示是不是系统消息try {os.writeUTF(str);os.flush();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}//给本线程外的其他客户端做出响应private void responseOther(String str) {for(Work entry: holder.values()) {if(!entry.equals(this)) {//给其他客户端转发此消息entry.response(str);}}}//释放相关资源private void release() {this.flg = false;ChatUtils.close(is,os,client);//一个客户端退出removeClient();}//一个客户端退出private void removeClient() {String name ="";for(ConcurrentHashMap.Entry<String,Work> entry: holder.entrySet()) {if(entry.getValue().equals(this)) {name = entry.getKey();break;}}holder.remove(name);}}

客户端:

package cn.liu.chat03;import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;/*** 对客户端再进行二次封装* Send类实现发数据* Receive类拿到数据* @author Administrator**/
public class Client {private Socket client;//客户端private String ip;//服务器ip地址private int serverPort;//服务器端口public Client(String ip, int serverPort) {this.ip = ip;this.serverPort = serverPort;try {this.client = new Socket(ip,serverPort);//创建一个客户端} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}//和服务器通信public void run() {System.out.println("--------------ChatClient-------------");new Thread(new Send(client)).start();new Thread(new Receive(client)).start();}
}
package cn.liu.chat03;import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;/*** 1.收到服务器的响应* 2.释放资源* @author Administrator**/
public class Receive implements Runnable{private DataInputStream is;private Socket client;private boolean flg;public Receive(Socket client) {super();this.client = client;try {this.is = new DataInputStream(client.getInputStream());} catch (IOException e) {e.printStackTrace();} this.flg = true;}@Overridepublic void run() {while(flg) {receiveData();}release(); }private void receiveData(){try {String str = is.readUTF();System.out.println(str);} catch (IOException e) {e.printStackTrace();}  }private void release() {this.flg = false;ChatUtils.close(is,client);}}
package cn.liu.chat03;import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;/*** 1.从控制台接收消息* 2.把消息发给服务器端* 3.释放资源* @author Administrator**/
public class Send implements Runnable{private DataOutputStream os;private Socket client;private boolean flg;public Send(Socket client) {super();this.client = client;try {this.os = new DataOutputStream(client.getOutputStream());} catch (IOException e) {e.printStackTrace();}this.flg = true;}@Overridepublic void run() {while(flg) {//从控制台获取消息,发送数据到服务器端sendData(input());}release();}//从控制台获取消息private String input() {Scanner ss = new Scanner(System.in);String str = ss.nextLine();return str;}//发送数据到服务器端private void sendData(String str) {try {os.writeUTF(str);os.flush();} catch (IOException e) {e.printStackTrace();}}//释放资源private void release() {this.flg = false;ChatUtils.close(os,client);}}

工具类:

package cn.liu.chat03;import java.io.Closeable;
import java.io.IOException;/*** 工具类* @author Administrator**/
public class ChatUtils {/*** 释放资源*/public static void close(Closeable... resource) {for(Closeable a:resource) {try {if(null!=a)a.close();} catch (IOException e) {e.printStackTrace();}}}
}

测试类:

package cn.liu.chat03;public class ClientTest {public static void main(String[] args) {Client ss= new Client("Dick",8848);ss.run();}
}
package cn.liu.chat03;public class TestServer {public static void main(String[] args) {Server ss = new Server(8848);ss.run();}
}

Socket编写一个简易的聊天室相关推荐

  1. 简单java socket_基于Java Socket实现一个简易在线聊天功能(一)

    最近做了一个项目,其中有一个在线网页交流的需求,好久没写代码了,手都生疏了,于是先写demo练练手,分享到脚本之家平台,以此做个记录,方便自己和大家使用. 先给大家说下实现步骤分这样几大步: 1.使用 ...

  2. Java编写一个原始的聊天室(线程、服务器-客户端)

    小白一只,刚看完梁勇老师的<Java语言程序设计后>,写了一个简单的聊天室,采用单服务器-多客户端的方式,能使多个用户同时对话,聊天记录被保存在本地文件中,可从客户端搜索聊天记录.界面用的 ...

  3. C 基于UDP实现一个简易的聊天室

    引言 本文是围绕Linux udp api 构建一个简易的多人聊天室.重点看思路,帮助我们加深 对udp开发中一些api了解.相对而言udp socket开发相比tcp socket开发注意的细节要少 ...

  4. 实现一个简易chat聊天室(4种方法)

    聊天室 提高服务器性能的方法有 I/O模型 阻塞I/O 非阻塞I/O I/O复用 SIGO信号 异步I/O 池 进程池 线程池 零拷贝读写 高级I/O函数 上下文切换和锁 pthread创建法 sel ...

  5. java实现一个简易网络聊天室

    题目要求 基本功能(必须实现和遵循的要求) 1.要求项目服务器端能稳定持续接收进入聊天室的人员,并能够在聊天室实时更新在线人数. 2.客户端可以持续不断的给服务器发送消息,中间不能丢失任何一条信息. ...

  6. 14级团队学习成果汇报 -- 利用express+socket.io搭建简易版聊天室

    周鹏,14级数理系,信息与计算科学大三学生.在LSGO软件技术团队负责前端部分,本图文是他的一个完整作品,代码可在Github上下载.

  7. 使用Unity制作一个简单的聊天室

    使用控制台作为一个服务器,在Unity中开发客户端,制作一个简易的聊天室,无论哪个客户端发送消息,其他的客户端都会实时的显示出来. 服务器代码 using System; using System.C ...

  8. python开发一个简单的聊天室

    使用python的twisted框架编写一个简单的聊天室 下面是基本架构 基本架构图 -- coding:utf-8 -- from twisted.internet.protocol import ...

  9. 简易QQ聊天室,socket多线程编程(C语言实现),简单易懂

    简易QQ聊天室 实现本功能,仅需了解socket套接字的使用,我已经将socket套接字的监听接受状态封装在了common.c中,相信你看了会有所收获,socket的连接也封装在common.c中. ...

最新文章

  1. Java反射 - 动态类加载和重载
  2. 【笔记】公钥密码学之RSA
  3. 类加载的三个阶段——加载、链接以及初始化,类的主动使用和被动使用
  4. Shell脚本入门基础
  5. 【测试点0分析】1009 Product of Polynomials (25 分)
  6. [vue] prop验证的type类型有哪几种?
  7. 神经网络与深度学习——TensorFlow2.0实战(笔记)(五)(Matplotlib绘图基础<1>python)
  8. 关于日志打印的几点建议以及非最佳实践
  9. 提交响应后无法调用sendredirect_DDD 指导应用垂直拆分后事务问题
  10. pandas将字符串转换成时间_数据处理利器 pandas 实例详解 (下)
  11. CCS软件报错“unresolved symbol remain”
  12. Linux文件系统:ext2/ext3
  13. 刷卡芯片CI520可直接PIN对PIN替换CV520支持SPI通讯接口
  14. 商业银行理财业务监督管理办法-2018年9月26日
  15. R语言七天入门教程二:认识变量与运算符
  16. 集中式发电景气下滑分布式光伏迎新机遇
  17. sql语句实现行转列的3种方法
  18. 5G+智慧灯杆发展生态峰会闭幕,专家精彩观点汇总
  19. 缓解论文写作压力的小妙招
  20. 黑马程序员的就业班入学考试整理

热门文章

  1. Unity 参数的基本设置
  2. 打印机共享后,要主机打印一张其他电脑才能打印
  3. 经济学原理---11 公共物品和共有资源-- 读书笔记
  4. CS-major日常问题归总(持续更新)
  5. mybatis字符串拼接
  6. 国人当自强 ~ 鸿蒙HarmonyOS2.0初体验
  7. linux用fdisk创建逻辑分区,Linux fdisk命令创建逻辑分区
  8. MySQL一些简单的操作
  9. CPU、内存与分布式
  10. php十进制转二进制,十进制转二进制