后端
- 创建主副线程组绑定端口号channel及childHandler
- 写childHandler的实现,在channel的pipeline 一系列的Handler
- 最后加入自己的ChatHandler的实现
代码
public class WSServer {
public static void main(String[] args) throws InterruptedException {
NioEventLoopGroup mainGroup = new NioEventLoopGroup();
NioEventLoopGroup subGroup = new NioEventLoopGroup();
try {
ServerBootstrap server = new ServerBootstrap();
server.group(mainGroup,subGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new WSServerInitialzer());
ChannelFuture future = server.bind(8188).sync();
future.channel().closeFuture().sync();
} finally {
mainGroup.shutdownGracefully();
subGroup.shutdownGracefully();
}
}
}
public class WSServerInitialzer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new ChunkedWriteHandler());
pipeline.addLast(new HttpObjectAggregator(1024*64));
pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
pipeline.addLast(new ChatHandler());
}
}
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
private static ChannelGroup channels= new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
String text = textWebSocketFrame.text();
System.err.println("[channelRead0]:"+text);
for (Channel channel : channels) {
channel.writeAndFlush(new TextWebSocketFrame("[channelRead0] server receved msg:"+ LocalDateTime.now()+"is"
+text
));
}
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
// super.handlerAdded(ctx);
System.err.println("[handlerAdded]:"+ctx.channel().id());
channels.add(ctx.channel());
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
super.handlerRemoved(ctx);
channels.remove(ctx.channel());
//一个客户端对应一个channel
System.err.println("[handlerRemoved]:"+ctx.channel().id());
}
}
Flutter实现移动端
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:web_socket_channel/io.dart';
import 'package:flutter/material.dart';
import 'package:web_socket_channel/web_socket_channel.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget{
@override
Widget build(BuildContext context){
final title = 'WebSocket Demo';
return new MaterialApp(
title:title,
home: new MyHomePage(
title: title,
channel: new IOWebSocketChannel.connect('ws://192.168.0.8:8188/ws'),//如果是本地直接使用IP地址而非localhost或127.0.0.1
),
);
}
}
class MyHomePage extends StatefulWidget{
final String title;
final WebSocketChannel channel;
MyHomePage({Key key,@required this.title,@required this.channel}): super(key: key);
@override
_MyHomePageState createState()=> new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>{
TextEditingController _controller = new TextEditingController();
@override
Widget build(BuildContext context){
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Padding(
padding: const EdgeInsets.all(20.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Form(
child: new TextFormField(
controller: _controller,
decoration: new InputDecoration(labelText: 'Send a message'),
),
),
new StreamBuilder(
stream: widget.channel.stream,
builder: (context, snapshot){
return new Padding(
padding: const EdgeInsets.symmetric(vertical: 24.0),
child: new Text(snapshot.hasData?'${snapshot.data}':''),
);
}),
],
),
),
floatingActionButton: new FloatingActionButton(
onPressed: _sendMessage,
tooltip: 'Send message',
child: new Icon(Icons.send),
),
);
}
void _sendMessage(){
if (_controller.text.isNotEmpty){
widget.channel.sink.add(_controller.text);
print("send message completed");
}
}
@override
void dispose(){
widget.channel.sink.close();
super.dispose();
}
}
Mui手机端实现移动端
MUI组件地址:http://dev.dcloud.net.cn/mui/snippet/
图标不足就用iconFont 地址 https://www.iconfont.cn/
调用android 用H5+ 地址:http://www.html5plus.org/doc/zh_cn/navigator.html
页面效果