赞
踩
首先记得引入nettycompile 'io.netty:netty-all:4.1.13.Final'
- public class Server {
- private static final int PORT = 8999;
-
- public static void main(String[] args) {
- // NioEventLoopGroup is a multithreaded event loop that handles I/O operation.
- EventLoopGroup bossGroup = new NioEventLoopGroup(); // 用于处理客户端的连接请求
- EventLoopGroup workerGroup = new NioEventLoopGroup(); // 用于处理与各个客户端连接的IO操作
-
- // ServerBootstrap is a helper class that sets up a server.
- ServerBootstrap serverBootstrap = new ServerBootstrap();
- serverBootstrap.group(bossGroup, workerGroup)
- .channel(NioServerSocketChannel.class) // 使用Java Nio的Selector来处理新连接接入
-
- // ChannelInitializer是一个特殊的Handler用来帮助用户配置新Channel,一般用于在channelPipeline中新建channelHandler
- .childHandler(new ChannelInitializer<SocketChannel>() {
- @Override
- protected void initChannel(SocketChannel ch) throws Exception {
- ch.pipeline().addLast(new EchoServerHandler());
- }
- })
- .option(ChannelOption.SO_BACKLOG, 128) // 对应bossGroup
- .childOption(ChannelOption.SO_KEEPALIVE, true); // 对应workerGroup
- try {
- ChannelFuture channelFuture = serverBootstrap.bind(PORT).sync(); // 等待接入
-
- // Wait until the server socket is closed.
- // In this example, this does not happen, but you can do that to gracefully
- // shut down your server.
- channelFuture.channel().closeFuture().sync();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } finally {
- workerGroup.shutdownGracefully();
- bossGroup.shutdownGracefully();
- }
- }
- }
ChannelInboundHandlerAdapter负责处理连接建立,收到消息。
- public class EchoServerHandler extends ChannelInboundHandlerAdapter {
- @Override
- public void channelActive(ChannelHandlerContext ctx) throws Exception {
- super.channelActive(ctx);
- System.out.println("connected from:" + ctx.channel().remoteAddress());
- }
-
- @Override
- public void channelInactive(ChannelHandlerContext ctx) throws Exception {
- super.channelInactive(ctx);
- }
-
- @Override
- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
- ByteBuf byt = (ByteBuf) msg;
- byte[] bytesSrc = new byte[byt.readableBytes()];
- byt.readBytes(bytesSrc);
- String data = new String(bytesSrc);
- System.out.println("received:" + data + " from:" + ctx.channel().remoteAddress());
- String response = "response: " + data;
-
- ByteBuf responseBuf = ctx.alloc().buffer(response.length());
- responseBuf.writeBytes(response.getBytes());
- ctx.channel().writeAndFlush(responseBuf);
- byt.release(); // 释放资源
- }
-
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
- cause.printStackTrace();
- ctx.close();
- }
- }
- public class MainActivity extends AppCompatActivity {
- private EditText mIpEt;
- private EditText mPortEt;
- private Button mConnBtn;
- private TextView mScreenTv;
- private EditText mInputEt;
- private Button mSendBtn;
-
- private SocketThread mSocketThread;
- private static Handler mMainHandler;
-
- public static final int MSG_CONNECT = 0x001;
- public static final int MSG_RECEIVE = 0x002;
- public static final int MSG_SEND = 0x003;
-
- public static final String DATA_RECEIVE = "data_receive";
- public static final String DATA_SEND = "data_send";
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- mIpEt = findViewById(R.id.main_ip_et);
- mPortEt = findViewById(R.id.main_port_et);
- mConnBtn = findViewById(R.id.main_connect_btn);
- mScreenTv = findViewById(R.id.main_screen_tv);
- mInputEt = findViewById(R.id.main_input_et);
- mSendBtn = findViewById(R.id.main_send_btn);
-
- // defalut value. Change it to your own server ip
- mIpEt.setText("172.16.62.65");
- mPortEt.setText("8999");
-
- mConnBtn.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- String ip = mIpEt.getText().toString();
- String port = mPortEt.getText().toString();
- if (TextUtils.isEmpty(ip) || TextUtils.isEmpty(port)) {
- Toast.makeText(MainActivity.this, "ip or port is null", Toast.LENGTH_SHORT).show();
- } else {
- connectToServer(ip, Integer.valueOf(port));
- }
- }
- });
-
- mSendBtn.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- String data = mInputEt.getText().toString();
- if (!TextUtils.isEmpty(data)) {
- mSocketThread.sendMessage(data);
- }
- }
- });
-
- // TODO handler may cause memory leaks
- mMainHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_CONNECT:
- Toast.makeText(MainActivity.this, "Connect to Server Success", Toast.LENGTH_SHORT).show();
- mConnBtn.setText("Connected");
- mConnBtn.setEnabled(false);
- break;
- case MSG_RECEIVE:
- Bundle data = msg.getData();
- String dataStr = data.getString(DATA_RECEIVE);
- CharSequence originData = mScreenTv.getText();
- String result = originData + "\n" + dataStr;
- mScreenTv.setText(result);
- break;
- }
- }
- };
- }
-
-
- private void connectToServer(String ip, int port) {
- mSocketThread = new SocketThread(ip, port);
- mSocketThread.start();
- }
-
- private static class SocketThread extends Thread {
- private Channel mChannel;
- private String mIp;
- private int mPort;
- private SendThread mSendThread;
-
- public SocketThread(String ip, int port) {
- this.mIp = ip;
- this.mPort = port;
- }
-
- @Override
- public void run() {
- EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
- Bootstrap clientBootStrap = new Bootstrap();
- clientBootStrap.group(eventLoopGroup)
- .channel(NioSocketChannel.class)
- .option(ChannelOption.TCP_NODELAY, true)
- .handler(new ChannelInitializer<SocketChannel>() {
- @Override
- protected void initChannel(SocketChannel ch) throws Exception {
- ch.pipeline().addLast(new EchoClientHandler(mMainHandler));
- }
- });
-
- try {
- // Start the client.
- ChannelFuture future = clientBootStrap.connect(mIp, mPort).sync();
- mChannel = future.channel();
- mSendThread = new SendThread(mChannel);
- mSendThread.start();
-
- // Wait until the connection is closed.
- mChannel.closeFuture().sync();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } finally {
- eventLoopGroup.shutdownGracefully();
- }
- }
-
- public void sendMessage(String data) {
- Handler socketHandler = mSendThread.getSocketHandler();
- Message message = socketHandler.obtainMessage();
- message.what = MSG_SEND;
- Bundle bundle = new Bundle();
- bundle.putString(DATA_SEND, data);
- message.setData(bundle);
- socketHandler.sendMessage(message);
- }
-
- }
-
- private static class SendThread extends Thread {
- private Handler mSocketHandler;
- private Channel mChannel;
-
- public SendThread(Channel channel) {
- mChannel = channel;
- }
-
- @Override
- public void run() {
- // init child thread handler
- if (mSocketHandler == null) {
- Looper.prepare();
- mSocketHandler = new Handler(Looper.myLooper()) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_SEND:
- String data = msg.getData().getString(DATA_SEND);
- ByteBuf byteBuf = Unpooled.buffer(data.length()); //使用非池化Buffer去申请内存,这里待优化
- byteBuf.writeBytes(data.getBytes());
- mChannel.writeAndFlush(byteBuf);
- break;
- }
- }
- };
- }
- Looper.loop();
- }
-
- public Handler getSocketHandler() {
- return mSocketHandler;
- }
- }
- }
ChannelInboundHandlerAdapter实现代码,用于处理连接建立、收到消息。
- public class EchoClientHandler extends ChannelInboundHandlerAdapter {
- private Handler mMainHandler;
-
- public EchoClientHandler(Handler handler) {
- mMainHandler = handler;
- }
- @Override
- public void channelActive(ChannelHandlerContext ctx) throws Exception {
- super.channelActive(ctx);
- mMainHandler.sendEmptyMessage(MainActivity.MSG_CONNECT);
- }
-
- @Override
- public void channelInactive(ChannelHandlerContext ctx) throws Exception {
- super.channelInactive(ctx);
- }
-
- @Override
- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
- ByteBuf byt = (ByteBuf) msg;
- byte[] bytesSrc = new byte[byt.readableBytes()];
- byt.readBytes(bytesSrc);
- String data = new String(bytesSrc);
- Message message = mMainHandler.obtainMessage();
- message.what = MainActivity.MSG_RECEIVE;
- Bundle extra = new Bundle();
- extra.putString(MainActivity.DATA_RECEIVE, data);
- message.setData(extra);
- mMainHandler.sendMessage(message);
-
- byt.release(); // 释放资源
- }
-
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
- cause.printStackTrace();
- ctx.close();
- }
- }
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:layout_margin="15dp">
-
- <EditText
- android:id="@+id/main_ip_et"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="ip address"/>
-
- <EditText
- android:id="@+id/main_port_et"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="port"
- android:inputType="number"/>
-
- <Button
- android:id="@+id/main_connect_btn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="Connect"/>
-
- <EditText
- android:id="@+id/main_input_et"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="message to server"/>
-
- <Button
- android:id="@+id/main_send_btn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="Send"/>
-
- <ScrollView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginTop="10dp">
- <TextView
- android:id="@+id/main_screen_tv"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="received message will be shown here"/>
- </ScrollView>
-
- </LinearLayout>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。