群聊的实现思路和私聊的实现非常类似。
不同的是:私聊时,服务端接收到消息后,只需要找出接收方的socket并发送消息即可
群聊时,服务端在接收到消息后需要遍历集合中所有的线程,找出除了发送方的所有客户端的socket,并发送消息
群聊思路:
在接口中增加新的消息类型
String MESSAGE_TO_ALL_MES = "7";//表示群发消息包
在该类中增加sendMessageToAll方法,实现群发功能
/**
* 群发消息功能
* @param content 内容
* @param senderId 发送者
*/
public void sendMessageToAll(String content,String senderId){
//构建 message
Message message = new Message();
message.setMesType(MessageType.MESSAGE_TO_ALL_MES);//设置消息类型是群发消息
message.setSender(senderId);
message.setContent(content);
message.setSendTime(new Date().toString());//发送时间也封装到 message对象中
System.out.println(senderId + " 对大家说 " + content);
//发送给服务端
try {//在管理线程的集合中,通过userId来获取线程,通过线程来获取对应的socket,再通过socket获取输出流
ObjectOutputStream oos =
new ObjectOutputStream(ManageClientConnectServerThread.getClientConnectServerThread(senderId).getSocket().getOutputStream());
oos.writeObject(message);
} catch (IOException e) {
e.printStackTrace();
}
}
在该类的run方法中增加新的逻辑业务,增加接收群发消息类型的判断,并在控制台显示
else if (message.getMesType().equals(MessageType.MESSAGE_TO_ALL_MES)) {
//接收到的是群发的消息
//就把服务器转发的消息,显示到控制台即可
System.out.println("\n" + message.getSendTime() + "\n" + message.getSender()
+ " 对大家说: " + "\n" + message.getContent());
}

在该类的内层循环中,调用群发功能的方法:
case "2":
System.out.println("请输入想对大家说的话");
String s = Utility.readString(100);
//调用一个方法,将消息封装成 message对象,发给服务端
messageClientService.sendMessageToAll(s,userId);
break;

在接口中增加新的消息类型
String MESSAGE_TO_ALL_MES = "7";//表示群发消息包
在该类中增加新的业务逻辑
else if (message.getMesType().equals(MessageType.MESSAGE_TO_ALL_MES)) {
//业务四:客户请求群发消息需要遍历管理线程的集合,把所有线程的socket都得到,然后将 message进行转发即可
//得到hm
HashMap<String, ServerConnectClientThread> hm = ManageClientThreads.getHm();
//遍历
Iterator<String> iterator = hm.keySet().iterator();
while (iterator.hasNext()) {
//取出所有userId
String onlineUserId = iterator.next().toString();
//取出除了发送者的所有用户id
if (!onlineUserId.equals(message.getSender())) {
//转发message
//从集合中取出线程,在线程中取出socket,根据socket获得输出流,将socket的输出流转化为对象输出流
ObjectOutputStream oos =
new ObjectOutputStream(hm.get(onlineUserId).getSocket().getOutputStream());
oos.writeObject(message);
}
}
}

在该类中增加方法,获取集合
//返回hashmap
public static HashMap<String ,ServerConnectClientThread> getHm(){
return hm;
}
运行程序:
1.运行服务端,进行监听
2.运行三个客户端,登录三个用户
3.在 用户uid=100 的账号发送群发消息
4.其他用户也接收到了消息
5.服务器端
功能实现完毕
只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您
需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc
在Rails自动生成的功能测试(test/functional/products_controller_test.rb)中,我看到以下代码:classProductsControllerTest我的问题是:方法调用products()在哪里/如何定义?products(:one)到底是什么意思?看代码,大概意思是“创建一个产品”,但是它是如何工作的呢?注意我是Ruby/Rails的新手,如果这些是微不足道的问题,我深表歉意。 最佳答案 如果您查看test/fixtures文件夹,您会看到一个products.yml文件。这是在您创建
我试图在Ubuntu14.04中使用Curl安装RVM。我运行了以下命令:\curl-sSLhttps://get.rvm.io|bash-sstable出现如下错误:curl:(7)Failedtoconnecttoget.rvm.ioport80:Networkisunreachable非常感谢解决此问题的任何帮助。谢谢 最佳答案 在执行curl之前尝试这个:echoipv4>>~/.curlrc 关于ruby-在Ubuntu14.04中使用Curl安装RVM时出错,我们在Stack
在我的一些Controller中,我有一个before_filter检查用户是否登录?用于CRUD操作。application.rbdeflogged_in?unlesscurrent_userredirect_toroot_pathendendprivatedefcurrent_user_sessionreturn@current_user_sessionifdefined?(@current_user_session)@current_user_session=UserSession.findenddefcurrent_userreturn@current_userifdefine
我有一个任务列表(名称、starts_at),我试图在每日View中显示它们(就像iCal)。deftodays_tasks(day)Task.find(:all,:conditions=>["starts_atbetween?and?",day.beginning,day.ending]end我不知道如何将Time.now(例如“2009-04-1210:00:00”)动态转换为一天的开始(和结束),以便进行比较。 最佳答案 deftodays_tasks(now=Time.now)Task.find(:all,:conditio
安装Rails时,一切都很好,但后来,我写道:rails-v和输出:/home/toshiba/.rvm/rubies/ruby-2.2.1/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in`require':cannotloadsuchfile--rails/cli(LoadError)from/home/toshiba/.rvm/rubies/ruby-2.2.1/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in`r
什么是0day漏洞?0day漏洞,是指已经被发现,但是还未被公开,同时官方还没有相关补丁的漏洞;通俗的讲,就是除了黑客,没人知道他的存在,其往往具有很大的突发性、破坏性、致命性。0day漏洞之所以称为0day,正是因为其补丁永远晚于攻击。所以攻击者利用0day漏洞攻击的成功率极高,往往可以达到目的并全身而退,而防守方却一无所知,只有在漏洞公布之后,才后知后觉,却为时已晚。“后知后觉、反应迟钝”就是当前安全防护面对0day攻击的真实写照!为了方便大家理解,中科三方为大家梳理当前安全防护模式下,一个漏洞从发现到解决的三个时间节点:T0:此时漏洞即0day漏洞,是已经被发现,还未被公开,官方还没有相
提供3种Ubuntu系统安装微信的方法,在Ubuntu20.04上验证都ok。1.WineHQ7.0安装微信:ubuntu20.04安装最新版微信--可以支持微信最新版,但是适配的不是特别好;比如WeChartOCR.exe报错。2.原生微信安装:linux系统下的微信安装(ubuntu20.04)--微信适配的最好,反应最快,但是微信版本只到2.1.1,版本太老,很多功能都没有。3.深度deepin-wine6安装微信:ubuntu20.04+系统deepin-wine6安装新版微信--综合比较好,当前个人使用此种方法1个月,微信版本3.4;没什么大问题,尚可。一、WineHQ7.0安装微信
require'pp'p*1..10这会打印出1-10。为什么这么简洁?您还可以用它做什么? 最佳答案 它是“splat”运算符。它可用于分解数组和范围并在赋值期间收集值。这里收集赋值中的值:a,*b=1,2,3,4=>a=1b=[2,3,4]在此示例中,内部数组([3,4])中的值被分解并收集到包含数组中:a=[1,2,*[3,4]]=>a=[1,2,3,4]您可以定义将参数收集到数组中的函数:deffoo(*args)pargsendfoo(1,2,"three",4)=>[1,2,"three",4]