首页 > 其他分享 >chap3

chap3

时间:2024-05-31 19:33:07浏览次数:16  
标签:allOut chap3 消息 println 线程 message 客户端

本文档描述了Server端接收到Client的消息并转发给所有客户端或私发给某个客户端

服务端为当前客户端创建一个线程,此线程接收当前客户端的消息并转发给所有客户端或私发给某个客户端

一、Server:

1.1.Server端添加将消息转化给客户端的代码。有用集合保存输出流,、从集合获取输出流,广播数据给所有人的方法sendMessage()、将消息发送给固定某个客户端的方法sendMessageToSomeone()

在Server端的ClientHandler线程类中添加如下代码(主要是在上一个文档的基础上添加返回消息给客户端的代码)。 

 

1.2.run()方法上边添加一个群发消息的方法sendMessage()还有另一个私发消息的方法sendMessageToSomeOne()

 

/**将消息发送给所有客户端*/
public void sendMessage(String message){
    System.out.println(message);
    synchronized (allOut) {
        //同步代码块synchronized(){}作用:
        //这里要求遍历集合时与增删元素互斥,因为迭代器要求遍历过程中不可以通过集合方法增删元素
        //这里用forEach循环迭代集合时,不能调用集合的put()add()和remove()方法否则抛异常。
        //所以应该把forEach循环放入到同步代码块synchronized(){}中
        //(因为:forEach循环会编译为Iterator迭代器方式)
        //for (PrintWriter o : allOut) {
        //    o.println(message);//从allOut集合中获取一个输出流o,再用输出流o的println返回数据给客户端
        //}
        //原本用List  allOut集合则用forEach循环时是直接调用的

        //换成Map allOut集合则应该先用allOut.values()方法获取所有value集合,再用forEach
        //遍历allOut的所有value
        Collection<PrintWriter> c = allOut.values();
        for(PrintWriter o : c){
            o.println(message);//从allOut集合中获取一个输出流o,再用输出流o的println返回数据给客户端
        }//循环完allOut集合中的所有输出流 可以将此message返回给每个客户端
    }
}
public void sendMessageToSomeone(String message){/**私聊功能*/
    //私聊消息的格式:   @对方昵称:聊天消息
    //私聊消息格式验证:  @.+:.+      //@开头然后有一个以上的字符,然后是":" , 最后也是一个以上的字符
    //                            //@张三: 你好
    if(message.matches("@.+:.+")){
        //从私聊信息message截取到对方的昵称(从聊天消息第1个字符开始截取到":"字符的位置<第0个字符@不需要>)
        // 比如截取 "@张三: 你好"  中的"张三"
        String toNickName = message.substring(1,message.indexOf(":"));
        //截取出要发送给对方的内容(从聊天消息的":"字符的后一个位置到消息的末尾之间的所有文字)
        String toMessage = message.substring(message.indexOf(":")+1);
        //从Map allOut集合通过对方的昵称作为key,获取他对应的输出流
        PrintWriter pw = allOut.get(toNickName);
        if(pw==null){//如果没有获取到输出流,则说明对方昵称对应的用户不存在(对方下线了)
       //从Map allOut集合获取发送消息的客户端的输出流,用此println()给发送消息的客户端返回 "用户[接收方昵称]不存在!"
            allOut.get(nickName).println("用户["+toNickName+"]不存在!");
        }else {
            //如果范传奇在控制台上输入:   @王克晶:晚上有空么?
            //则"王克晶"为toNickname    "晚上有空么?" 为toMessage       
            //   最终要向王克晶发送的消息内容是: “ 范传奇悄悄对你说:晚上有空么?”
            pw.println(nickName+"悄悄对你说:"+toMessage);
            //调用saveMessage()将该消息保存到数据库中      
        }
    }else{//私聊格式错误(如果发送的消息message不是以@开头)
        //就从Map  allOut集合获取发送消息的客户端对应的输出流,用println()返回给发送消息的客户端  "私聊格式错误..."
        allOut.get(nickName).println("私聊格式错误(@对方昵称:聊天内容),请重新输入");
    }
}

 

 

二、Client端:

客户端需要编写一个单独的线程类ServerHandler,用于接收服务端返回的数据 (main方法调用的start()方法内发送消息<main线程发送消息>)  (是为了发送消息的同时还能接收消息)。

2.1.ServerHandler类

编写用于接收服务端返回的消息的线程类:

/**该线程任务负责不断地接收来自服务端返回的消息*/
private class ServerHandler implements Runnable{
    public void run() {
        try {
            //通过socket获取输入流,用于读取服务端发送过来的消息
            InputStream in = socket.getInputStream();
            InputStreamReader isr = new InputStreamReader(in, StandardCharsets.UTF_8);
            BufferedReader br = new BufferedReader(isr);
            //循环读取来自服务端发送过来的消息并输出到客户端控制台上
            String message;
            while((message = br.readLine())!=null){
                System.out.println(message);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 2.2.创建线程类对象并启动:

在Client类中的start方法中, 在打印”昵称不能为空”的下边添加如下启动线程的代码(并将此接收服务端消息的线程设置为后台线程。)

 

 运行效果:

 

 

 

 


 

                                                                                                                                                                       By   zhaoyq   2024-05-31

 

标签:allOut,chap3,消息,println,线程,message,客户端
From: https://www.cnblogs.com/zhaoyongqi/p/18225179

相关文章

  • chap3 变量与函数
    变量与函数1.变量1.赋值:=2.新值数据类型不一定与旧数据相同x=10 print(x) x=true print(x)3.变量=值,变量可以理解为“标签”4.变量的命名规则:-必须以字母或下划线开头-命名可由字母数字下划线组成-大小写有区别-避免保留字命名5.保留字:查看:importkeywo......
  • pythonChap3变量与函数
    变量与操作变量用=赋值新的值会覆盖掉旧的值新值的数据类型不一定要与旧的相等变量命名规则:必须以字母或下划线(_)开头命名可由字母、数字和下划线组成大小写敏感尽量避免使用保留字命名保留字:['False','None','True','peg_parser','and','as','assert','async......
  • Python Chap3 变量与函数
    #变量与函数##变量1.变量是一个**名字**,它所指代的是一段数据2.使用=来对这段数据的区域进行赋值x=53.新的值会覆盖掉旧的值4.新值的数据类型不必与旧值相同##变量命名规则1.必须以字母或者下划线_开头2.命名可由字母,数字或下划线组成3.大小写敏感4.尽量避免使......
  • 数据库系统笔记 - chap3 - SQL
    IntroductiontoSQLSQL(StructuredQueryLanguage),是关系数据库的标准查询语言。SQL的特点:综合统一SQL集数据定义语言(DDL),数据操纵语言(DML),数据控制语言(DCL)功能于一体。高度非过程化SQL只要提出“做什么”,而无须指明“怎么做”,因此无须了解存取路径。存取路径的选择......
  • 微机原理笔记 - chap3 - Intel处理器指令系统及汇编语言
    汇编语言基础数据定义:数据传送、算术运算、跳转指令MOV指令“先目的操作数,再源操作数。”MOV指令需要遵循的规则:两个操作数的尺寸必须一致。两个操作数不能同时为内存操作数。movreg,regmovmem,regmovreg,memmovmem,immmovreg,immmovvar2,var1......
  • python 画图 chap3
    importmatplotlib.pyplotaspltplt.rcParams['font.sans-serif']=['SimHei']plt.rcParams['axes.unicode_minus']=Falseplt.figure()p=data.boxplot(return_type='dict'......
  • chap3 多分支结构
    本章主要涉及内容用二分支结构和if-else语句、多分支结构和else-if语句以及switch的使用方法if的常见错误:1.忘记加大括号{}不加大括号if只能执行它的下一句为了保险......
  • chap3
    1,字符型变量定义时类型名:char在函数scanf用“%c”输入当读入“/”和“%”时,要考虑后面那个数是否为02,字符型常量是一对单引号及其所括起来的字符,例如‘=’3,输入和输......