首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > JAVA > Java Web开发 >

高分求救:怎么用 ServerSocketChannel & SocketChannel做的一个接收客户端的数据包?(在线)

2012-03-04 
高分求救:如何用 ServerSocketChannel & SocketChannel做的一个接收客户端的数据包?(在线) 1、客户端程序可

高分求救:如何用 ServerSocketChannel & SocketChannel做的一个接收客户端的数据包?(在线)

1、客户端程序可以连上来,但发送一次之后,发送第2次,服务器就出问题了,主要是在run()方法中的while   (selector.select()   >   0)这句上,本来selector.select()应该是阻塞的,但第2次发送后,就不阻塞了,立刻返回,而且为false。请问这是为什么?


2、连第二个客户端的时候,程序也没有检测到,key.isAcceptable()始终为false,是怎么回事?

代码如下:
public   void   init(int   portNumber)   throws   Exception{
//分配一个ServerSockerChannel
serverChannel   =   ServerSocketChannel.open();
//从ServerSocketChannel里获得一个对应的Socket
serverSocket   =   serverChannel.socket();
//生成一个Selector
selector   =   Selector.open();
//把socket绑定到端口上
serverSocket.bind(new   InetSocketAddress(portNumber));
//serverChannel为非bolck
serverChannel.configureBlocking(false);
//通过Selector注册ServerSocketChannel
//serverChannel.register(selector,SelectionKey.OP_ACCEPT);
serverChannel.register(selector,SelectionKey.OP_ACCEPT);
}

protected   void   registerChannel(Selector   selector,SelectableChannel   channel,int   ops)   throws   Exception{
if   (channel   ==   null){
return;
}
channel.configureBlocking(false);
channel.register(selector,ops);
}

protected   void   processData(SelectionKey   key)   throws   Exception{
SocketChannel   socketChannel   =   (SocketChannel)key.channel();
USSDMessage   message   =   (USSDMessage)messageFactory.createMessage( " ")   ;
USSDEvent   event   =   null;
int   count;
buffer.clear();
//读取所有的数据
while((count   =   socketChannel.read(buffer))   > 0){
System.out.println( "count: "+count);
buffer.flip();
while(buffer.hasRemaining()){
message.buildMessageFromBuffer(buffer);
if(message   !=   null){
int   intCmdId   =   message.getCmdId();
        if(intCmdId   ==   Constant.USSD_MESSAGE_COMMAND_SURVEILLANCE_REQ)
        {  
        event   =   new   USSDEvent(buffer);
                                this.applicationContext.publishEvent(event);
  }
        message   =   this.resetUSSDMessage(message);        
        buffer.clear();
ByteBuffer   newBuffer   =   buffer.slice()   ;
  message.appendToBuffer(newBuffer);
  System.out.println( "buffer   write   to   socketChannel   begin! ");
//   message.buildMessageFromBuffer(buffer);
  socketChannel.write(buffer);     //在socket里写数据
  System.out.println( "buffer   write   to   socketChannel   end! ");
  }
}
buffer.clear();     //清空buffer
//count   =   -1;
//break;
}
if(count   <   0){
//count <0,说明已经读取完毕
socketChannel.close();
}

}
private   void   processData(SocketChannel   socketChannel)   throws   Exception
{
USSDMessage   message   =   (USSDMessage)messageFactory.createMessage( " ")   ;
USSDEvent   event   =   null;
int   count;
buffer.clear();
//读取所有的数据
while((count   =   socketChannel.read(buffer)   )   > 0){


//         socketChannel.read(buffer);
buffer.flip();
while(buffer.hasRemaining()){
message.buildMessageFromBuffer(buffer);
if(message   !=   null){
int   intCmdId   =   message.getCmdId();
        if(intCmdId   ==   Constant.USSD_MESSAGE_COMMAND_SURVEILLANCE_REQ){  
        event   =   new   USSDEvent(buffer);
                                this.applicationContext.publishEvent(event);
  }
        message   =   this.resetUSSDMessage(message);        
          buffer.clear();
  ByteBuffer   newBuffer   =   buffer.slice()   ;
  message.appendToBuffer(newBuffer);
  socketChannel.write(buffer);     //在socket里写数据
}
}
buffer.clear();     //清空buffer
//count   =   -1;
//break;
}
//if(count   <   0){
////count <0,说明已经读取完毕
//socketChannel.close();
//}
}

public   void   startWork()   throws   Exception{
while(true){
int   n   =   selector.select();//获得IO准备就绪的channel数量
System.out.println( "selector.select(): "+n);
if(n   ==   0){
continue;
}
//用一个iterator   返回Selector的selectedkeys
Iterator   it   =   selector.selectedKeys().iterator();
System.out.println( "selector.selectedKeys: "+selector.selectedKeys().size());

//处理每一个SelectionKey
while(it.hasNext()){
SelectionKey   key   =   (SelectionKey)it.next();

//判断是否有新的连接到达
if(key.isAcceptable()){
ServerSocketChannel   server   =   (ServerSocketChannel)key.channel();
SocketChannel   channel   =   server.accept();
channel.configureBlocking(false);
registerChannel(selector,channel,SelectionKey.OP_READ);
//doWork(channel);
processData(channel);
}
//判断是否有数据在此channel里需要读取
if(key.isReadable()){
processData(key);
}
it.remove();
}
}

}
调用:
public   void   run()   {
try   {
init(this.serverPort);
startWork();
}   catch   (Exception   e)   {
e.printStackTrace();
}
}
请高人指点!!!!!

[解决办法]
package nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.Iterator;
import java.util.Set;

public class SocketNIOServer
{
private ByteBuffer _buffer = ByteBuffer.allocate(8);
private IntBuffer _intBuffer = _buffer.asIntBuffer();
private SocketChannel _clientChannel = null;
private ServerSocketChannel _serverChannel = null;

public void start()
{
try
{
openChannel();
waitForConnection();
}
catch(IOException e)
{


System.err.println(e.toString());
}
}

private void openChannel() throws IOException
{
_serverChannel = ServerSocketChannel.open();
// 非阻塞的加法服务器 首先在openChannel方法中加入语句
_serverChannel.configureBlocking(false);// 设置成为非阻塞模式
_serverChannel.socket().bind(new InetSocketAddress(10000));
System.out.println( "服务器通道已经打开 ");
}

// private void waitForConnection() throws IOException
// {
// while(true)
// {
// _clientChannel = _serverChannel.accept();
// if(_clientChannel != null)
// {
// System.out.println( "新的连接加入 ");
// processRequest();
// _clientChannel.close();
// }
// }
// }
// 重写WaitForConnection方法的代码如下,使用非阻塞方式
private void waitForConnection() throws IOException
{
Selector acceptSelector = SelectorProvider.provider().openSelector();
/*
* 在服务器套接字上注册selector并设置为接受accept方法的通知。
* 这就告诉Selector,套接字想要在accept操作发生时被放在ready表上,因此,允许多元非阻塞I/O发生。
*/
SelectionKey acceptKey = _serverChannel.register(acceptSelector,SelectionKey.OP_ACCEPT);
int keysAdded = 0;
/* select方法在任何上面注册了的操作发生时返回 */
while((keysAdded = acceptSelector.select()) > 0)
{
// 某客户已经准备好可以进行I/O操作了,获取其ready键集合
Set readyKeys = acceptSelector.selectedKeys();
Iterator i = readyKeys.iterator();
// 遍历ready键集合,并处理加法请求
while(i.hasNext())
{
SelectionKey sk = (SelectionKey)i.next();
i.remove();
ServerSocketChannel nextReady = (ServerSocketChannel)sk.channel();
// 接受加法请求并处理它
Socket _clientSocket = nextReady.accept().socket();
processRequest();
_clientSocket.close();
}
}
}

private void processRequest() throws IOException
{
_buffer.clear();
_clientChannel.read(_buffer);
int result = _intBuffer.get(0) + _intBuffer.get(1);
_buffer.flip();
_buffer.clear();
_intBuffer.put(0,result);
_clientChannel.write(_buffer);
}

public static void main(String[] args)
{
new SocketNIOServer().start();
}
}

热点排行