udp协议服务端单线程-多客户端交互例子
服务端
package Demo5;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
public class NioUdpServer {
//http://blog.csdn.net/foart/article/details/47608475
//http://www.cnblogs.com/rainy-shurun/p/5756501.html
//这个要多琢磨琢磨
private int port = 8000;
private DatagramChannel channel;
private Selector selector = null;
public void initNioUdpServer() throws IOException
{
//创建udp连接通道
channel = DatagramChannel.open();
//创建通道管理器
selector = Selector.open();
//设置通道为非阻塞性通道(不会创建线程)
channel.configureBlocking(false);
//将该通道绑定对应的端口
channel.socket().bind(new InetSocketAddress(port));
//为通道注册通道管理器,并且注册一个可读就绪事件
channel.register(selector, SelectionKey.OP_READ);
}
//启动轮询来接受来自客户端的数据报文
public void listen() throws IOException
{
System.out.println("new nio server start");
while(true)
{
//有通道就绪时(即select()的返回值大于0时),不阻塞,否则,阻塞,不会有任何的通道加入
selector.select();
System.out.println("new udp server channel join");
Iterator<?> it = this.selector.selectedKeys().iterator();
while(it.hasNext())
{
SelectionKey key = (SelectionKey) it.next();
it.remove();//此处负责把udp连接断掉
clientHandler(key); //处理来自客户端的连接(通道的各种状态)
}
}
}
private void clientHandler(SelectionKey key) throws IOException
{
if(key.isReadable()){
handlerRead(key);
}
}
//udp的接受客户端数据和响应的过程
private void handlerRead(SelectionKey key) throws IOException {
//接受数据过程
DatagramChannel channel = (DatagramChannel) key.channel();
ByteBuffer buf = ByteBuffer.allocate(1024);
buf.clear();//固定写法
InetSocketAddress address =(InetSocketAddress)channel.receive(buf);//接受来自客户端通道的数据
buf.flip();//固定写法
String content = "";
while(buf.hasRemaining())
{
buf.get(new byte[buf.limit()]);
content += new String(buf.array());
}
System.out.println("udp server content:"+content);
buf.clear();
//发送数据过程
ByteBuffer buf2 = ByteBuffer.allocate(65500);
buf2.clear();
buf2.put("udp server put data process!!".getBytes());
buf2.flip();
this.channel.send(buf2,address);
}
public void close() throws IOException
{
this.channel.close();
this.selector.close();
}
public static void main(String[] args) throws IOException {
NioUdpServer server = new NioUdpServer();
server.initNioUdpServer();
server.listen();
//server.close();
}
}
客户端:
package Demo5;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
public class NioUdpClient {
private DatagramChannel channel;
private String ip = "127.0.0.1";
private int port = 8000;
private Selector selector;
public void initUdpClient() throws IOException
{
channel = DatagramChannel.open();
selector = Selector.open();
channel.configureBlocking(false);
channel.connect(new InetSocketAddress(ip, port));
//有个现象:
//两个控制台君出现不接受数据也不发送数据,仅仅启动了两端
// new nio client start
// new nio server start
//原因猜测:注册任意事件都是与通道相关的,但是,很明显当客户端启动时,通道的各种就绪状态还没出现,所以需要手动
//channel.write(ByteBuffer.wrap("client send msg".getBytes()));
//来引发服务器端通道相关的就绪状态
channel.write(ByteBuffer.wrap("client send msg".getBytes()));
channel.register(selector, SelectionKey.OP_READ);
}
public void listen() throws IOException
{
System.out.println("new nio client start");
while(true)
{
selector.select();
System.out.println("new udp client channel join");
Iterator<?> it = this.selector.selectedKeys().iterator();
while(it.hasNext())
{
SelectionKey key = (SelectionKey) it.next();
it.remove();
handler(key);
}
}
}
public void handler(SelectionKey key) throws IOException
{
if(key.isReadable())
{
handlerRead( key);
}
}
public void handlerRead(SelectionKey key) throws IOException
{
DatagramChannel channel = (DatagramChannel) key.channel();
//接受来自服务端的数据报文
ByteBuffer buf = ByteBuffer.allocate(65500);
buf.clear();
channel.receive(buf);
buf.flip();
String content = "";
while(buf.hasRemaining())
{
buf.get(new byte[buf.limit()]);
content += new String(buf.array());
}
buf.clear();
System.out.println("udp client content :" + content);
}
public void close() throws IOException
{
this.channel.close();
this.selector.close();
}
public static void main(String[] args) throws IOException {
NioUdpClient client = new NioUdpClient();
client.initUdpClient();
client.listen();
//client.close();
}
}
测试:
eclipse下
1、启动server:
2、启动一个Client:
3、启动另外一个Client:
4、查看服务端的结果(打印了两遍msg,测试准确):