tcp,udp,netty 记录
udp发送广播:
获取本机wifi ip地址,最后一位改为255,发送全c网段广播
private fun getWIFIIp() : InetAddress{
val toString = NetworkUtils.getIpAddressByWifi().toString()
val lastIndexOf = toString.lastIndexOf(".")
val substring = toString.substring(0,lastIndexOf+1)
return InetAddress.getByName(substring+"255")
}
创建DatagramSocket对象,发送广播或点对点发送消息,端口号:15001
@Synchronized fun sendDataMsg(host : InetAddress = getWIFIIp() ,msg : String){
try {
val datagramSocket = DatagramSocket()
datagramSocket.broadcast = true
val datagramPacket = DatagramPacket(msg.toByteArray(),msg.toByteArray().size, host, 15001)
datagramSocket.send(datagramPacket)
LogUtils.i(msg)
datagramSocket.close()
}catch (e : Exception){
ToastUtils.showShort("udp 发送失败")
}
}
接收指定端口号的消息:
@Synchronized fun receiveDataMsg(port: Int,listener: Listener){
diskIO.execute {
var datagramSocket : DatagramSocket? = null
try {
val byteArray = ByteArray(1024)
// val byName = InetAddress.getByName(NetworkUtils.getIpAddressByWifi())
datagramSocket = DatagramSocket(port)
datagramSocket.broadcast = true
val datagramPacket = DatagramPacket(byteArray, byteArray.size)
while (isReceive){
datagramSocket.receive(datagramPacket)
val data = String(datagramPacket.data, 0, datagramPacket.length)
LogUtils.i(“udp read data ::$data”,datagramPacket.address,datagramPacket.length)
val indexOf = data.indexOf("{")
listener.onReceive(data.substring(indexOf, data.length))
}
}catch (e : Exception){
e.printStackTrace()
ToastUtils.showShort(“udp 接收异常”)
}finally {
datagramSocket?.close()
}
}
}
发送组播,ip地址指定为:224.0.0.1
val byteArray = msg.toByteArray()
val multicastSocket = MulticastSocket()
multicastSocket.timeToLive = 1
val byName = InetAddress.getByName("224.0.0.1")
multicastSocket.joinGroup(byName)
val datagramPacket = DatagramPacket(byteArray,0,byteArray.size,byName,port)
multicastSocket.send(datagramPacket)
multicastSocket.close()
接收组播:
val byteArray = ByteArray(1024)
val byName = InetAddress.getByName("224.0.0.1")
val multicastSocket = MulticastSocket(port)
multicastSocket.timeToLive = 1
multicastSocket.joinGroup(byName)
val datagramPacket = DatagramPacket(byteArray, byteArray.size)
multicastSocket.receive(datagramPacket)
tcp socket链接:
初始化socket对象:
mRunFlag = true;
try {
mSocket = new Socket(mHost, mPort);
mInputStream = new DataInputStream(mSocket.getInputStream());
mOutputStream = new DataOutputStream(mSocket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
mRunFlag = false;
}
if (mRunFlag) {
//连接成功开启一个新的线程读取数据
mReadThread = new ReadThread();
mReadThread.start();
}
开启读线程,循环读取消息:
try {
String text = mInputStream.readLine();
Log.d(TAG, "read: " + text);
//如果收到null数据表示连接出错,使用break退出循环
if (text == null) {
mRunFlag = false;
break;
}
notifyReceive(text);
} catch (IOException e) {
mRunFlag = false;
e.printStackTrace();
}
}
用outputstream发送消息
if (mOutputStream != null && text != null) {
try {
mOutputStream.write(text.getBytes());
mOutputStream.flush();
return true;
} catch (IOException e) {
mRunFlag = false;
e.printStackTrace();
}
}
netty使用:
build.gradle里添加依赖:
implementation 'io.netty:netty-all:4.0.47.Final'
初始化 nio,设置编码,解码器等:
nioEventLoopGroup = NioEventLoopGroup()
bootstrap = Bootstrap()
bootstrap?.group(nioEventLoopGroup)
?.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,3000) //超时时间
?.channel(NioSocketChannel::class.java)
?.handler(object : ChannelInitializer<SocketChannel>() {
override fun initChannel(ch: SocketChannel?) {
ch?.pipeline()?.addLast(object : MessageToByteEncoder<String>() { //自定义 编码器
override fun encode(ctx: ChannelHandlerContext?, msg: String?, out: ByteBuf?) {
out?.writeBytes(msg?.toByteArray())
}
})
?.addLast(IdleStateHandler(0,0,20)) //读取空闲,写入空闲,所有空闲
// ?.addLast(FixedLengthFrameDecoder(1024)) //固定长度 解码器
// ?.addLast(DelimiterBasedFrameDecoder(1024,delimiter)) //限定符 解码器
// ?.addLast(LengthFieldBasedFrameDecoder(1024_00,0,4,0,12)) //指定长度 解码器
// ?.addLast(TcpDecode()) //自定义解码器
?.addLast(HandlerAdapter()) //读取消息handler
}
})
tcp连接,host:IP地址,port:端口号
try {
bootstrap?.connect(mHost, mPort)?.addListener { //异步连接
if (it.isSuccess){ //连接成功
LogUtils.i("connect $mHost")
ch = (it as ChannelFuture).channel() //拿到 通道,通过 channel 发送消息
isStop = false
mListener?.connectSuccess(mHost,mPort) //连接成功回调
}else{
(it as ChannelFuture).channel().eventLoop().schedule({ //连接失败
stopConnect()
connect(mHost,mPort)
},2,TimeUnit.SECONDS) //2s 后重连
}
}?.sync()
}catch (e: Exception){
e.printStackTrace()
}
断开连接:
if (ch != null && ch!!.isOpen){ //断开连接
ch?.close()
ch = null
}
if (nioEventLoopGroup != null){
nioEventLoopGroup?.shutdownGracefully()
nioEventLoopGroup = null
}
通过 channel 发送消息
if (ch != null && ch!!.isOpen){
ch?.writeAndFlush("$s")?.addListener {
if (!it.isSuccess){ //发送失败
mListener?.writeFail(s)
}
}
}
读取消息,心跳包发送:
inner class HandlerAdapter : ChannelInboundHandlerAdapter(){
override fun channelRead(ctx: ChannelHandlerContext?, msg: Any?) { //未定义解码器,所以msg 为 bytebuf
val str = if (msg is ByteBuf) bytebufToString(msg) else ""
LogUtils.i(str)
mListener?.resultMsg(mHost,mPort,str)
}
override fun exceptionCaught(ctx: ChannelHandlerContext?, cause: Throwable?) {
cause?.printStackTrace()
ctx?.close()
}
@Synchronized fun bytebufToString(buf : ByteBuf) : String{
var str = ""
if(buf.hasArray()) { // 处理堆缓冲区
str = String(buf.array(), buf.arrayOffset() + buf.readerIndex(), buf.readableBytes())
} else { // 处理直接缓冲区以及复合缓冲区
val bytes = ByteArray(buf.readableBytes())
buf.getBytes(buf.readerIndex(), bytes)
str =String(bytes, 0, buf.readableBytes())
}
return str
}
override fun userEventTriggered(ctx: ChannelHandlerContext?, evt: Any?) {
if (evt is IdleStateEvent) {
when (evt.state()) {
IdleState.ALL_IDLE -> { // 前面设置 20ms 没有读取,发送消息,为所有空闲状态,发送心跳包
val baseReponseBean = BaseReponseBean(30, 1, Heart(mPwd), gatewayid = 12345678)
writeData(baseReponseBean.toString())
}
}
}else{
super.userEventTriggered(ctx, evt)
}
}
override fun channelInactive(ctx: ChannelHandlerContext?) { // tcp 断开连接
super.channelInactive(ctx)
ctx?.channel()?.eventLoop()?.schedule({
LogUtils.i("channel in active and reset connect")
stopConnect()
connect(mHost,mPort,mPwd)
},2,TimeUnit.SECONDS) //2s 后 重连
ctx?.close()
}
}