首页 技术 正文
技术 2022年11月15日
0 收藏 348 点赞 3,608 浏览 5966 个字

说明:基于netty 3.9.2的udp协议实现的(如果你使用的版本是4.X或5.X,请参考其他方法);程序的逻辑结构是,客户端发送给服务端一串数据,服务器端返回给客户端“A”。在进行游戏开发时需要对udp的丢包进行处理,可以利用服务器端的返回值进行相关处理,以确定是否重发,这方面具体没有实现。

文章结构:

一、服务器端

1、UDPServer

2、UdpChannelPipelineFactory

3、UDPServerHandler

二、客户端

1、UDPClient

2、UDPClientChannelPipelineFactory

3、UDPClientHandler

三、ScanGetPort获取一个可用的端口号

一、服务器端

1、UDPServer

初始化一个ConnectionlessBootstrap,setPipelineFactory,绑定一个端口号。ScanGetPort是一个工具类就是,获取一个可用的端口号,源代码在最后面贴出。

package com.ls.udp.server;import java.net.InetSocketAddress;
import java.util.concurrent.Executors;import org.jboss.netty.bootstrap.ConnectionlessBootstrap;
import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory;import com.andy.server.util.ScanGetPort;public class UDPServer { public final int PORT;
public UDPServer(int port){
PORT=port;
}
private ConnectionlessBootstrap bootstrap;
void start(){
//init the bootstrap
bootstrap=new ConnectionlessBootstrap(new NioDatagramChannelFactory(Executors.newCachedThreadPool()));
bootstrap.setPipelineFactory(new UdpChannelPipelineFactory());
bootstrap.bind(new InetSocketAddress(PORT));
System.out.println("server start at:"+":"+PORT);
} public static void main(String[] args) {
/*
* 获取一个可用的端口号
*/
int port= new ScanGetPort().getPot(8080);
new UDPServer(port).start();
}}

2、UdpChannelPipelineFactory

注册一个handler

package com.ls.udp.server;import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;public class UdpChannelPipelineFactory implements ChannelPipelineFactory{ /**
* set the channel pipeline
*
*/
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("handler", new UDPServerHandler());
return pipeline;
}
}

3、UDPServerHandler

handler类

package com.ls.udp.server;import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.DynamicChannelBuffer;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;public class UDPServerHandler extends SimpleChannelUpstreamHandler{ /**
* 对于ChannelHandler,
* 是UDP与TCP区别的核心所在。
* 大家都知道UDP是无连接的,
* 也就是说你通过 MessageEvent 参数对象的 getChannel() 方法获取当前会话连接,
* 但是其 isConnected() 永远都返回 false。
* UDP 开发中在消息获取事件回调方法中,
* 获取了当前会话连接 channel 对象后可直接通过 channel 的 write 方法发送数据给对端 channel.write(message, remoteAddress),
* 第一个参数仍然是要发送的消息对象,
* 第二个参数则是要发送的对端 SocketAddress 地址对象。
* 这里最需要注意的一点是SocketAddress,在TCP通信中我们可以通过channel.getRemoteAddress()获得,
* 但在UDP通信中,我们必须从MessageEvent中通过调用getRemoteAddress()方法获得对端的SocketAddress 地址。
*/
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception { ChannelBuffer buffer = (ChannelBuffer)e.getMessage();
byte[] recByte=buffer.copy().toByteBuffer().array(); String msg=new String(recByte);
System.out.println("from client:"+msg); ChannelBuffer responseBuffer= new DynamicChannelBuffer(1); responseBuffer.writeBytes("A".getBytes()); //write to the client
e.getChannel().write(responseBuffer, e.getRemoteAddress()); super.messageReceived(ctx, e);
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
throws Exception {
super.exceptionCaught(ctx, e);
}}

二、客户端

(基本结构和服务器端很像,不再赘述)

1、UDPClient

package com.ls.udp.client;import java.net.InetSocketAddress;
import java.util.Scanner;import org.jboss.netty.bootstrap.ConnectionlessBootstrap;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.DynamicChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory;public class UDPClient { private ConnectionlessBootstrap bootstrap;
private Channel channel;
public void start(){
//init the bootstrap
bootstrap=new ConnectionlessBootstrap(new NioDatagramChannelFactory());
bootstrap.setPipelineFactory(new UDPClientChannelPipelineFactory());
bootstrap.setOption("localAddress", new InetSocketAddress(10001));
channel=bootstrap.bind();
} public void writebytes(byte[] bt,InetSocketAddress isa){
if(bootstrap==null){
this.start();
}
ChannelBuffer responseBuffer= new DynamicChannelBuffer(12); responseBuffer.writeBytes(bt);
channel.write(responseBuffer, isa);
} public static void main(String[] args) { UDPClient uClient=new UDPClient(); Scanner scanner=new Scanner(System.in);
String lienString=scanner.nextLine();
while(!lienString.equals("bye")){ uClient.writebytes(lienString.getBytes(), new InetSocketAddress("192.168.1.107",8080));
lienString=scanner.nextLine();
}
}}

2、UDPClientChannelPipelineFactory

package com.ls.udp.client;import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
public class UDPClientChannelPipelineFactory implements ChannelPipelineFactory{ /**
* set the channel pipeline
*
*/
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("handler", new UDPClientHandler());
return pipeline;
}
}

3、UDPClientHandler

package com.ls.udp.client;import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;public class UDPClientHandler extends SimpleChannelUpstreamHandler{ @Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception { ChannelBuffer buffer = (ChannelBuffer)e.getMessage();
byte[] recByte=buffer.copy().toByteBuffer().array(); String msg=new String(recByte);
System.out.println("from server:"+msg); super.messageReceived(ctx, e);
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
throws Exception {
super.exceptionCaught(ctx, e);
}}

三、ScanGetPort获取一个可用的端口号

package com.andy.server.util;import java.io.IOException;
import java.net.ServerSocket;
/**
* get the port
* @author red
*
*/
public class ScanGetPort {
public synchronized int getPot(int first){
for(int i=first;i<65535;++i){
ServerSocket ss=null;
try {
ss= new ServerSocket(i);
} catch (IOException e) {
//e.printStackTrace();
}finally{
if(ss!=null){
if(ss.isBound()){
try {
ss.close();
System.out.println(i);
return i;
} catch (IOException e) {
e.printStackTrace();
} }
}
}
}
return -1;
}
}
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,992
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,506
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,349
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,134
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,766
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,844