Android 之 网络通信- TCP/UDP

1.TCP通信

  netty

​一、依赖配置

build.gradle中配置最新Netty依赖:

dependencies {
    implementation 'io.netty:netty-all:4.1.97.Final' // 截至2025年8月最新稳定版[4,6](@ref)
}

、基本使用

1. 封装工具类

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class NettyClient {
    private static final int RECONNECT_DELAY = 3; // 重连间隔(秒)
    private EventLoopGroup workerGroup;
    private Channel channel;
    private final String host;
    private final int port;
    private NettyListener listener;

    public NettyClient(String host, int port) {
        this.host = host;
        this.port = port;
    }

    // 初始化连接
    public void connect() {
        workerGroup = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(workerGroup)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new StringDecoder());   // 字符串解码
                            pipeline.addLast(new StringEncoder());   // 字符串编码
                            pipeline.addLast(new ClientHandler(listener)); // 业务处理器
                        }
                    });
            
            // 异步连接
            ChannelFuture future = bootstrap.connect(host, port).addListener((ChannelFutureListener) f -> {
                if (!f.isSuccess()) scheduleReconnect(); // 连接失败触发重连
            });
            channel = future.sync().channel();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    // 消息发送
    public void sendMessage(String msg) {
        if (channel != null && channel.isActive()) {
            channel.writeAndFlush(msg);
        }
    }

    // 重连机制
    private void scheduleReconnect() {
        workerGroup.schedule(this::connect, RECONNECT_DELAY, TimeUnit.SECONDS);
    }

    // 释放资源
    public void shutdown() {
        if (channel != null) channel.close();
        if (workerGroup != null) {
            Future<?> future = workerGroup.shutdownGracefully();
            future.syncUninterruptibly();
        }
    }

    // 设置消息监听器
    public void setListener(NettyListener listener) {
        this.listener = listener;
    }

    // 内部处理器
    private static class ClientHandler extends SimpleChannelInboundHandler<String> {
        private final NettyListener listener;

        ClientHandler(NettyListener listener) {
            this.listener = listener;
        }

        @Override
        protected void channelRead0(ChannelHandlerContext ctx, String msg) {
            if (listener != null) listener.onMessageReceived(msg); // 消息回调
        }

        @Override
        public void channelActive(ChannelHandlerContext ctx) {
            if (listener != null) listener.onConnectionStatusChanged(true); // 连接建立
        }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) {
            if (listener != null) listener.onConnectionStatusChanged(false); // 连接断开
        }
    }

    // 状态监听接口
    public interface NettyListener {
        void onMessageReceived(String message);
        void onConnectionStatusChanged(boolean isConnected);
    }
}

2. Activity调用示例

public class MainActivity extends AppCompatActivity implements NettyClient.NettyListener {
    private NettyClient nettyClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // 初始化Netty客户端
        nettyClient = new NettyClient("192.168.1.100", 8080);
        nettyClient.setListener(this);
        new Thread(() -> nettyClient.connect()).start(); // 在子线程启动连接

        // 发送消息示例
        findViewById(R.id.btn_send).setOnClickListener(v -> {
            String msg = "Hello Server!";
            nettyClient.sendMessage(msg);
        });
    }

    // 实现监听回调
    @Override
    public void onMessageReceived(final String message) {
        runOnUiThread(() -> {
            TextView tv = findViewById(R.id.tv_response);
            tv.setText("收到: " + message); // 主线程更新UI
        });
    }

    @Override
    public void onConnectionStatusChanged(final boolean isConnected) {
        runOnUiThread(() -> {
            String status = isConnected ? "已连接" : "连接断开";
            Toast.makeText(this, "状态: " + status, Toast.LENGTH_SHORT).show();
        });
    }

    @Override
    protected void onDestroy() {
        nettyClient.shutdown(); // 释放资源防止内存泄漏
        super.onDestroy();
    }
}

4.心跳保活

在ClientHandler中添加:
// 每30秒发送心跳
ctx.executor().scheduleAtFixedRate(() -> 
    ctx.writeAndFlush("HEARTBEAT"), 0, 30, TimeUnit.SECONDS
);

2.UDP通信

netty

​一、依赖配置

build.gradle中配置最新Netty依赖:

dependencies {
    implementation 'io.netty:netty-all:4.1.97.Final' // 截至2025年8月最新稳定版[4,6](@ref)
}

、基本使用

 ​​1. UDP工具类封装

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.CharsetUtil;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Netty UDP 客户端工具类
 * 功能:消息发送、接收回调、资源释放
 */
public class UdpClient {
    private final Bootstrap bootstrap;
    private final NioEventLoopGroup group;
    private Channel channel;
    private final ExecutorService threadPool;
    private UdpListener listener;

    public UdpClient() {
        group = new NioEventLoopGroup();
        bootstrap = new Bootstrap();
        threadPool = Executors.newSingleThreadExecutor();
        
        bootstrap.group(group)
            .channel(NioDatagramChannel.class)
            .option(ChannelOption.SO_BROADCAST, true) // 支持广播
            .handler(new ChannelInitializer<NioDatagramChannel>() {
                @Override
                protected void initChannel(NioDatagramChannel ch) {
                    ch.pipeline().addLast(new SimpleChannelInboundHandler<DatagramPacket>() {
                        @Override
                        protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) {
                            // 主线程回调 → 子线程处理
                            threadPool.execute(() -> {
                                String msg = packet.content().toString(CharsetUtil.UTF_8);
                                if (listener != null) {
                                    listener.onMessageReceived(msg);
                                }
                            });
                        }
                    });
                }
            });
    }

    /**
     * 绑定本地端口(Android需动态申请端口)
     * @param port 本地端口(0表示随机端口)
     */
    public void bind(int port) {
        threadPool.execute(() -> {
            try {
                ChannelFuture future = bootstrap.bind(port).sync();
                channel = future.channel();
                if (listener != null) listener.onBindSuccess(port);
            } catch (Exception e) {
                if (listener != null) listener.onError(e);
            }
        });
    }

    /**
     * 发送消息
     * @param targetIp   目标IP
     * @param targetPort 目标端口
     * @param message    消息内容
     */
    public void send(String targetIp, int targetPort, String message) {
        if (channel == null || !channel.isActive()) return;
        
        threadPool.execute(() -> {
            try {
                ByteBuf buf = Unpooled.copiedBuffer(message, CharsetUtil.UTF_8);
                InetSocketAddress target = new InetSocketAddress(targetIp, targetPort);
                channel.writeAndFlush(new DatagramPacket(buf, target));
            } catch (Exception e) {
                if (listener != null) listener.onError(e);
            }
        });
    }

    /**
     * 释放资源
     */
    public void shutdown() {
        if (channel != null) channel.close();
        group.shutdownGracefully();
        threadPool.shutdown();
    }

    /**
     * 设置事件监听
     */
    public void setListener(UdpListener listener) {
        this.listener = listener;
    }

    public interface UdpListener {
        void onBindSuccess(int localPort); // 绑定成功
        void onMessageReceived(String msg); // 收到消息
        void onError(Throwable cause);      // 发生异常
    }
}

​2. Activity调用示例​

public class MainActivity extends AppCompatActivity implements UdpClient.UdpListener {
    private UdpClient udpClient;
    private TextView tvStatus;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvStatus = findViewById(R.id.tv_status);

        // 1. 初始化UDP客户端
        udpClient = new UdpClient();
        udpClient.setListener(this);
        udpClient.bind(0); // 绑定随机端口

        // 2. 发送消息示例
        findViewById(R.id.btn_send).setOnClickListener(v -> {
            String ip = "192.168.1.100"; // 目标服务器IP
            int port = 8080;            // 目标服务器端口
            String msg = "Hello UDP!";
            udpClient.send(ip, port, msg);
        });
    }

    // 3. 实现监听回调
    @Override
    public void onBindSuccess(final int localPort) {
        runOnUiThread(() -> tvStatus.setText("本地端口: " + localPort));
    }

    @Override
    public void onMessageReceived(final String msg) {
        runOnUiThread(() -> Toast.makeText(this, "收到: " + msg, Toast.LENGTH_SHORT).show());
    }

    @Override
    public void onError(final Throwable cause) {
        runOnUiThread(() -> tvStatus.setText("错误: " + cause.getMessage()));
    }

    @Override
    protected void onDestroy() {
        udpClient.shutdown(); // 释放资源
        super.onDestroy();
    }
}

3.注意权限

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

4.注意

Android 9+ 默认禁用UDP广播,需在代码中开启:

bootstrap.option(ChannelOption.SO_BROADCAST, true);

3.WebService

ksoap2-android

​一、依赖配置

build.gradle中配置最新Netty依赖:

implementation 'com.google.code.ksoap2-android:ksoap2-android:3.6.4'

、基本使用

1. 封装工具类

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SoapClientUtil {
    private static final String DEFAULT_NAMESPACE = "http://example.com/";
    private static final String DEFAULT_URL = "http://example.com/soap-endpoint";
    private static final int THREAD_POOL_SIZE = 5;
    private static ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);

    // 异步请求(推荐)
    public static void callAsync(String methodName, Map<String, Object> params, 
                                boolean isDotNet, SoapCallback callback) {
        threadPool.submit(() -> {
            try {
                Object result = callSync(methodName, params, isDotNet);
                callback.onSuccess(result);
            } catch (Exception e) {
                callback.onError(e);
            }
        });
    }

    // 同步请求
    public static Object callSync(String methodName, Map<String, Object> params, 
                                 boolean isDotNet) throws Exception {
        SoapObject request = new SoapObject(DEFAULT_NAMESPACE, methodName);
        
        // 添加请求参数
        if (params != null) {
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                request.addProperty(entry.getKey(), entry.getValue());
            }
        }

        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
        envelope.setOutputSoapObject(request);
        envelope.dotNet = isDotNet; // 适配 .NET 平台

        HttpTransportSE transport = new HttpTransportSE(DEFAULT_URL);
        transport.debug = true; // 开启调试日志
        
        try {
            transport.call(DEFAULT_NAMESPACE + methodName, envelope);
            return envelope.getResponse(); // 返回原始响应(可转为 SoapObject/String)
        } catch (Exception e) {
            throw new RuntimeException("SOAP请求失败: " + e.getMessage());
        }
    }

    // 回调接口
    public interface SoapCallback {
        void onSuccess(Object result);
        void onError(Exception e);
    }
}

2. Activity调用示例

// 初始化参数
String methodName = "getWeather";
Map<String, Object> params = new HashMap<>();
params.put("cityName", "Beijing");
boolean isDotNet = true; // .NET 服务需设为 true

// 发起异步请求
SoapClientUtil.callAsync(methodName, params, isDotNet, new SoapClientUtil.SoapCallback() {
    @Override
    public void onSuccess(Object result) {
        if (result instanceof SoapObject) {
            SoapObject response = (SoapObject) result;
            String temperature = response.getPropertyAsString("temperature");
            String weather = response.getPropertyAsString("weather");
            Log.d("SOAP", "北京天气: " + weather + ",温度: " + temperature);
        }
    }

    @Override
    public void onError(Exception e) {
        Log.e("SOAP", "请求失败: " + e.getMessage());
    }
});

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值