【发布时间】:2013-01-15 16:07:10
【问题描述】:
我正在为多人游戏实现简单的网络服务器。我只是想弄清楚Netty。
我通过 telnet 测试服务器。我所做的是将消息广播到所有频道。它工作顺利。我还可以在关闭事件时从地图中删除频道,这很好。
但问题是,如果其中一个客户端意外断开,在关闭回调之前,调用发送方断开通道的 messageReceived 回调。
如何正确忽略来自断开连接的客户端的消息?
我在messagedReceived 中使用StringBuffer,但对于这种情况StringBuffer.toString 也不是正确的字符串。最后断开的通道向其他通道和自身广播无意义的消息,当接收通道本身时抛出异常Connection reset by peer
这是正常的,因为频道本身暂时不可用。
这里是代码;
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
System.out.println();
System.out.println("------------------");
Channel current = e.getChannel();
System.out.println("SenderChannel:"+current.getId());
if(!current.isOpen())
System.out.println("Not Open");
ChannelBuffer buf = (ChannelBuffer) e.getMessage();
StringBuffer sbs = new StringBuffer();
while(buf.readable()) {
sbs.append((char) buf.readByte());
}
String s = sbs.toString();
System.out.println(s);
String you = "You:" + s;
String other = "Other:" + s;
byte [] uResponse = you.getBytes();
byte [] otherResponse = other.getBytes();
Iterator iterator = channelList.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry pairs = (Map.Entry)iterator.next();
Integer key = (Integer)pairs.getKey();
Channel c = (Channel)pairs.getValue();
System.out.println("ReceiverChannel:"+c.getId());
if(key != current.getId())
c.write(ChannelBuffers.wrappedBuffer(otherResponse));
else
c.write(ChannelBuffers.wrappedBuffer(uResponse));
}
}
@Override
public void channelDisconnected(ChannelHandlerContext ctx,
ChannelStateEvent e){
Channel ch = e.getChannel();
channelList.remove(ch.getId());
System.out.println();
System.out.println("*****************");
System.out.println("DisconnectEvent:"+ch.getId());
System.out.println("*****************");
System.out.println();
ch.close();
}
【问题讨论】:
-
与问题和答案无关:您可以使用 StringBuilder 而不是 StringBuffer。在使用的范围内不需要同步。
-
StringBuilder 是有道理的,但是对于您的其余评论,我没明白吗?
-
:) 同步需要资源。因此,使用不需要同步的非线程安全类将为您节省一些 cpu%
-
好的,我明白了,但是@Fildor 问题的答案呢
-
恐怕我没有。除了采用 Soroush 的概念。如果连接本身不是用户登录或退出的“状态”,则必须保持上下文观察该状态,并且必须在写入时检查该状态并相应地过滤消息。