欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

使用 Netty 进行 UDP 网络编程 博客分类: java编程  

程序员文章站 2024-03-06 20:12:14
...
使用 Netty 进行 UDP 网络编程

    在正式开始之前,首先介绍一下TCP和UDP协议。对于做过网络开发的朋友来说,这两个协议应该都不陌生,在此仅摘录网上对两个协议的介绍给大家,仅供参考。
TCP与UDP区别
    TCP---传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。
    UDP---用户数据报协议,是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快
    可以看出,UDP与TCP的主要区别在于:UDP是无连接的,而这一点便是在使用netty进行开发时最重要的区别点了。

    首先,在ChannelFactory 的选择上,UDP的通信选择 NioDatagramChannelFactory,TCP的通信我们选择的是NioServerSocketChannelFactory;在Bootstrap的选择上,UDP选择的是ConnectionlessBootstrap,而TCP选择的是ServerBootstrap。下面是一个UDP通信服务器端的启动程序类:


import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.concurrent.Executors;

import org.apache.log4j.xml.DOMConfigurator;
import org.jboss.netty.bootstrap.ConnectionlessBootstrap;
import org.jboss.netty.channel.socket.DatagramChannelFactory;
import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

import com.game.netty.network.ServerPipelineFactory;

/** 
* 	作者:chenpeng  
*	E-mail:46731706@qq.com  
* 	创建时间:2012-7-16 上午10:52:30  
* 	netty udp 通信测试 
*/ 
public class ServerTest {

	public static void main(String[] args) {
		int port = 8888;
		DOMConfigurator.configureAndWatch("config/log4j.xml");
		ApplicationContext factory = new FileSystemXmlApplicationContext(
				new String[] { "config/propholder.xml" });
		DatagramChannelFactory udpChannelFactory = new NioDatagramChannelFactory(
				Executors.newCachedThreadPool());
		ConnectionlessBootstrap bootstrap = new ConnectionlessBootstrap(udpChannelFactory);
		
		ServerPipelineFactory udpServerFactory =(ServerPipelineFactory)factory.getBean("serverPipelineFactory");
		bootstrap.setPipelineFactory(udpServerFactory);
		SocketAddress serverAddress = new InetSocketAddress(port);
		bootstrap.bind(serverAddress);
		System.out.println(port+" Server is starting……");
		
	}

}



   对于编解码器decoder和Encoder,以及ChannelPipelineFactory,UDP开发与TCP并没有什么区别,在此不做详细介绍。

    对于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 地址

    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("服务器收到消息:" + msg);

        Random random = new Random();
        int rspWord = random.nextInt(10000);
        System.out.println("服务器写出消息:" + rspWord);

        ChannelBuffer response = new DynamicChannelBuffer(12);
        response.readBytes(rspWord);
        e.getChannel().write(response, e.getRemoteAddress());
    }



选择netty的UDP进行网络游戏开发时,不能忽视的一个问题就是由于UDP的不稳定性造成的丢包是否需要回传。也就是说在发生丢包情况时我们需要建立一个检测机制来确认是否需要重新发送丢包数据,机制相对简单,这里不再赘述。