最近项目中用到了 socket 服务器 异步处理信息
访问量有万人左右,
开始用的是 java的 NIO 非阻塞模式配置的 socket 但是 运行起来还是会有阻塞情况发生,部分代码:
private void initTCP(int port){
try {
//分别实例化一个选择器,一个服务器端可选择通道
selector = Selector.open();
ServerSocketChannel ssc = ServerSocketChannel.open();

ssc.socket().bind(new InetSocketAddress(port));
// 设置非阻塞  注册信息
ssc.configureBlocking(false);
ssc.register(selector, SelectionKey.OP_ACCEPT);

threadSelector.start();

} catch (IOException e) {
e.printStackTrace();
}
}

private InetAddress TCP_IP = null;
private int TCP_PORT = 0;
Thread threadSelector = new Thread(){
public void run(){
try {

while(true){
// 选择 select 得到 连接数 这里会出现 阻塞 直到有连接为止
selector.select();
TCPiterator = selector.selectedKeys().iterator();

new Thread(){
public void run(){
while(TCPiterator.hasNext()){
SelectionKey selectionKey = TCPiterator.next();

TCPiterator.remove(); // 删除此消息
// 在当前线程内处理
handlerSelectionKey(selectionKey);
}
}
}.start();

}
} catch (IOException e) {
e.printStackTrace();
}
}
};这样编写人一多就会卡死的,
在网上看到异步的调用模式,用到 AsynService 方法
但是百度上找了很多都没有相关的资料,只有几篇 google 上的 例子代码,
http://code.google.com/p/asyn4j/wiki/user_guide
http://www.iteye.com/topic/746277照着做了一遍后,发现
直接调用 测试 方法可以运行, 然后把我的 socket 放进去后一直报 空指针错误测试方法直接可以用:
public void asyinit() throws IOException{
server=new ServerSocket(10000);
AsynService asynService = AsynServiceImpl.getService(300,3000L,3,2,2000L);
// 启动服务
asynService.init();
// 异步回调对象
AsynCallBack back = new AsynCallBack() {

@Override
public void doNotify() {
// startAccept();
abc();
}
};
for(int i=0;i<100;i++){
// 添加异步工作 - TargetService 的test 方法,方法参数 asynej+i
asynService.addWork(Asyn_ServiceTest.class,"abc", new Object[]{}, back);
// asynService.addAsynWork(new AsynWorkEntity(Asyn_ServiceTest.class,"startAccept"));
}
}

public void abc(){
System.out.println("回调函数");

}加上自己的 socket 就报错public void asyinit() throws IOException{
server=new ServerSocket(10000);
AsynService asynService = AsynServiceImpl.getService(300,3000L,3,2,2000L);
// 启动服务
asynService.init();
// 异步回调对象
AsynCallBack back = new AsynCallBack() {

@Override
public void doNotify() {
startAccept();
// abc();
}
};
for(int i=0;i<100;i++){
// 添加异步工作 - TargetService 的test 方法,方法参数 asynej+i
asynService.addWork(Asyn_ServiceTest.class,"startAccept", new Object[]{}, back);
// asynService.addAsynWork(new AsynWorkEntity(Asyn_ServiceTest.class,"startAccept"));
}
}


public void startAccept(){
try{
socket=server.accept();
// 侦听信息

}catch(Exception e){
e.printStackTrace();
}

}
还望各位大神求解啊java  异步 socket 

解决方案 »

  1.   

    1 错误的stack异常信息,不然不大好分析。
    2 server现在是全局变量,最好在addWork的时候,以参数的形式传进去。asynService.addWork(Asyn_ServiceTest.class,"startAccept", new Object[]{server}, back);public void startAccept(Object serverPara) {
        ServerSocket server = (ServerSocket) serverPara;
        // 省略
    }
    最好还是把异常的信息发出来吧。
      

  2.   


    异常信息如上, 报的是空指针  
    socket = server.accept();  这行报错.
      

  3.   


    asynService.addWork(Asyn_ServiceTest.class,"startAccept", new Object[]{server}, back);
    这句话应该是产生了Asyn_ServiceTest的新的实例,而你的server这个变量估计没有定义成static的,如果没有定义为static的,那么Asyn_ServiceTest产生新的实例后,server这个变量就是null.而下面的赋值语句,根本就没作用,因为你产生了新的实例Asyn_ServiceTest。server=new ServerSocket(10000);public void startAccept(){
            try{
            socket=server.accept();
            // 侦听信息
             
            }catch(Exception e){
                e.printStackTrace();
            }
             
        }以上的方法的执行实例是新产生的,而你又没有给server赋值,所以就nullPointerException了建议还是以参数的形式将server传进去。见1楼
      

  4.   

    back = new AsynCallBack() {
    @Override
    public void doNotify() {

    startAccept(server);
    asynService.addWork(Asyn_ServiceTest.class,"startAccept", new Object[]{server}, back);
    }
    };
    // 添加异步工作 - TargetService 的test 方法,方法参数 asynej+i
    asynService.addWork(Asyn_ServiceTest.class,"startAccept", new Object[]{server}, back);
    // asynService.addWork(TargetService.class, "test",new Object[]{"abc"},new TargetBack()); }

    public void startAccept(Object serverPra){
    try{
    ServerSocket server = (ServerSocket) serverPra;
    System.out.println(server);
    socket=server.accept();
    System.out.println(socket.getInetAddress()+":"+socket.getPort()+"\tcome in");

    // 侦听信息

    }catch(Exception e){
    e.printStackTrace();
    }

    }
    传递数据过去确实很有用, 问题解决了 真心感谢一楼的啊
      

  5.   

    追问: 产生新的实例后, 会不会对实例里的其他 数据操作有影响.是不是最好把 startAccept单独写到一个类中??
      

  6.   

    ->追问: 产生新的实例后, 会不会对实例里的其他 数据操作有影响
    产生新的实例后,全局变量都会重新初始化。你在addWork之前的所有赋值都会变得毫无意义了。->是不是最好把 startAccept单独写到一个类中??
    这样显得更加的清晰,明了。这个类的职责就是一个worker类。
      

  7.   

    现在我要实现的是在 startAccept 中进行接收用户的信息 每接收一个就记录下来放到一个 list 中
    然后对 list 进行操作, 也就是说我想要 这个类和我其他 的类进行交互,但是 每次调用 的话都会重新初始化,
    那我如何使他接收到的信息都储存起来呢, 
      

  8.   

    或者说是 AsynService 中有没有什么机制能回传 一些参数 呢,我看了下这下面这个方法, 里面有个 
    AsynCallBack call() 这个方法, 是不是有用呢, 如果 是的话该如何使用呢, AsynWork asynWork = new AsynWork() {

    @Override
    public int getWeight() {
    // TODO Auto-generated method stub
    return 0;
    }

    @Override
    public String getThreadName() {
    // TODO Auto-generated method stub
    return null;
    }

    @Override
    public AsynCallBack getAnycResult() {
    // TODO Auto-generated method stub
    return null;
    }

    @Override
    public AsynCallBack call() throws Exception {
    // TODO Auto-generated method stub
    return null;
    }
    };