错误在于:当你的代码在执行完while(!stop)之后,而没有执行accept之前,如果执行了quit,那么可想而知,你的socket将会被关闭,尽管这是stop被置成true,但是已经过了循环检测语句,所以在你执行accept的时候程序将爆出异常socket closed!你可以考虑不需要在quit的时候close.对,是这样子的。
public void quit(){
    stop=true;
    //这里给serverSocket发一个临时的连接请求
    ......
    //
    try {
        Thread.sleep(200);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    serverSocket.close();
}

解决方案 »

  1.   

    catch异常退出public class SocketListener extends Thread {
        private boolean stop=false;
        private ServerSocket serverSocket = new ServerSocket(......);
        public void run(){
            while(!stop){
                try{
                  Socket socket=serverSocket.accept();//这里会抛出异常
                }catch(Excetion e){
                     break;
                }
                new ClientThread(socket).start;
                //ClientThread是一个线程类,处理socket,并包含了socket.close()
                //注意:这里是ServerSocket,在serverSocket.close()时会有异常
                //请不要与socket.close()混淆
    }
      

  2.   

    下面是我写的,希望有用对你:
    PoolManager,SafeBufferedReader分别是连接池管理器和安全读入器。/**
     * The server to monitor all tasks which comes from all client-side in LAN.
     *
     * @version $version 1.0
     * @author <a href="mailto:[email protected]" ><b>[email protected]</b></a>
     */import java.util.ArrayList;
    import java.util.StringTokenizer;import java.io.InputStreamReader;
    import java.io.BufferedReader;
    import java.io.IOException;import java.net.InetAddress;
    import java.net.Socket;
    import java.net.ServerSocket;
    import java.net.SocketTimeoutException;import java.sql.Connection;
    import java.sql.SQLException;
    import java.sql.Statement;import seu.yuch.sql.PoolManager;
    import seu.yuch.Constants;public class TaskMonitorServer extends Thread 
    implements Constants
    {
    private int port = DEFAULT_PORT;          //initialize port
    private int timeout = DEFAULT_TIMEOUT; //timeout private PoolManager pools = null; /**
     * Constructor.
     *
     */
    public TaskMonitorServer() {
    this( DEFAULT_PORT,DEFAULT_TIMEOUT );
    } /**
     * Constructor.
     *
     * @param port int.
     * @param timeout long.
     */
    public TaskMonitorServer( int port,int timeout ) {
    this.port = port;
    this.timeout = timeout;
    } /**
     * Sets the interval.
     *
     * @param interval long.
     */
    public void setTimeOut( int timeout ) {
    this.timeout = timeout;
    } /**
     * Sets the port.
     *
     * @param port int.
     */
    public void setPort( int port ) {
    this.port = port;
    }

    /**
     * Set connection pool manager
     * 
     * @param PoolManager
     */
    public void setPoolManager( PoolManager pools ) {
    this.pools = pools;
    } /**
     * Get connection pool manager.
     *
     * @return PoolManager.
     */
    public PoolManager getPoolManager() {
    return this.pools;
    }

    /**
     * Close server and dispose all resources
     *
     */
    public void release() {
    if( pools != null ) {
    pools.release();
    }
    } /**
     * Starts to run server.
     *
     */
    public void run() {
    try
    {
    ServerSocket server = new ServerSocket( port );
    server.setSoTimeout( timeout );
    while( true ) {
    Socket listen = null;
    try
    {
    listen = server.accept();
    ProcessConnectionThread cc =
    new ProcessConnectionThread( listen );
    }
    catch ( IOException e )
    {
    System.out.println( "无法监听到来的客户连接!" );
    }
    }
    }
    catch ( SocketTimeoutException e )
    {
    System.out.println( "服务器Socket超时!" );
    if( pools != null ) {//close all connection in pool
    pools.release();
    }
    return;
    }
    catch ( IOException e ) {
    System.out.println( "Starting server thread error!!" );
    if( pools != null ) {//close all connection in pool
    pools.release();
    }
    return;
    }
    } /**
     * Thread to process the activity information coming from client sides.
     *
     */
    class ProcessConnectionThread extends Thread {
    private Socket client = null;
    private SafeBufferedReader is = null;
       
    public ProcessConnectionThread( Socket s ) { // constructor
    client = s;
    try {
    is = new SafeBufferedReader( new BufferedReader( 
    new InputStreamReader( client.getInputStream() ) ) );
    } catch ( IOException e ) {
    System.out.println( "读取客户端资料异常: " + e.getMessage() );
    }
    this.start(); // Thread starts here...this start() will call run()
    }
     
    public void run() {
    Connection conn = null;
    Statement st = null;
    try {
    conn = pools.getConnection( "sqlserver" );
    st = conn.createStatement(); InetAddress inet = client.getInetAddress();
    String ip = inet.toString().substring(1); //clinet side's IP String activity = is.readLine();  //a activity item
    while( activity != null ) {
    //write a item about client's activity information into database
    StringTokenizer items = new StringTokenizer( activity,"***" );
    ArrayList infos = new ArrayList();
    while( items.hasMoreTokens() ) {
    infos.add( items.nextToken() );
    }
    StringBuffer buffer = new StringBuffer( "insert into" );
    if( ((String)infos.get(1)).equalsIgnoreCase("CPU") ) {
    String usage = (String)infos.get(2);
    buffer.append( " client_cpu values(\'" + ip + "\'"
    + ",\'" + (String)infos.get(0) + "\'"
    + ",\'" + ( Integer.valueOf(usage.trim()).intValue() ) + "\')" );
    }
    else if( ((String)infos.get(1)).equalsIgnoreCase("NET") ) {
    buffer.append(
    " client_net values(\'" + ip + "\'"
    + ",\'" + (String)infos.get(0) + "\'" );
    String[] infoitems = ((String)infos.get(2)).split( "###" );
    buffer.append( ",\'" + Integer.valueOf(infoitems[0].trim()).intValue() + "\'" );
    buffer.append( ",\'" + infoitems[1] + "\'" );
    buffer.append( ",\'" + infoitems[2] + "\'" );
    buffer.append( ",\'" + Integer.valueOf(infoitems[3].trim()).intValue() + "\'" );
    buffer.append( ",\'" + infoitems[4] + "\'" );
    buffer.append( ",\'" + Integer.valueOf(infoitems[5].trim()).intValue() + "\'" );
    buffer.append( ",\'" + Integer.valueOf(infoitems[6].trim()).intValue() + "\')" );
    }
    else {
    buffer.append( " client_activity values(\'" + ip + "\'" );
    buffer.append( ",\'" + (String)infos.get(0) + "\'" );
    buffer.append( ",\'" + (String)infos.get(1) + "\'" );
    buffer.append( ",\'" + (String)infos.get(2) + "\')" );
    }

    System.out.println( buffer.toString() );
    st.execute( buffer.toString() );

    //read next item
    activity = is.readLine();
    }

    if( st != null ) {//closse statement
    st.close();
    }
    if( conn != null ) {//return connection into pools
    pools.freeConnection( "sqlserver",conn );
    }
    }
    catch ( SQLException e ) {
    System.out.println( "数据库操作异常: " + e.getMessage() );
    }
    catch ( IOException e ) {
    System.out.println( client + " 断开连接!" + e.getMessage() );
    }
    }
    }

    /**
     * Test this application server.
     *
     */
    public static void main( String args[] ) {
    TaskMonitorServer server = new TaskMonitorServer();
    server.setTimeOut( 0 );//infinite wait
    PoolManager pools = PoolManager.getInstance();
    server.setPoolManager( pools );
    server.run();
    }
    }
      

  3.   

    那我也贴一个吧,不过我做的工程稍微大了一点,看起来可能费点劲,我尽量把主要的组件贴上,有时间我会放在blog上。有什么问题可以联系我msn:[email protected]
    package com.counsel.square.server.impls;import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.net.ServerSocket;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.ServerSocketChannel;
    import java.nio.channels.SocketChannel;
    import java.util.Iterator;import EDU.oswego.cs.dl.util.concurrent.LinkedQueue;import com.counsel.square.server.eventdomains.LifeCycleEventDomain;
    import com.counsel.square.server.eventdomains.ServerEventDomain;
    import com.counsel.square.server.helpers.LifeCycleHelper;
    import com.counsel.square.server.interfaces.Command;
    import com.counsel.square.server.interfaces.Event;
    import com.counsel.square.server.interfaces.EventDispatcher;
    import com.counsel.square.server.interfaces.EventDomain;
    import com.counsel.square.server.interfaces.EventSource;
    import com.counsel.square.server.interfaces.KeySpace;
    import com.counsel.square.server.interfaces.LifeCycle;
    import com.counsel.square.server.interfaces.Server;
    import com.counsel.square.server.utils.StackTraceUtils;/**
     * @author 王橙森
     * 
     * TODO To change the template for this generated type comment go to Window -
     * Preferences - Java - Code Style - Code Templates
     */
    public class ServerImpl implements Server { private Thread serviceThread; private boolean isStarted = false; private String name; private EventDispatcher serverEventDispatcher; private Selector selector; private int servicePort; private ServerSocketChannel ssc; private LinkedQueue commandQueue;

    private LifeCycleHelper lcHelper; public ServerImpl(String name, int servicePort, LifeCycle life) {
    this.name = name;
    this.servicePort = servicePort;
    init();
    cradleFrom(life);
    } /*
     * (non-Javadoc)
     * 
     * @see com.counsel.square.server.interfaces.Server#init()
     */
    private void init() {
    serviceThread = new Thread(new Runnable() {
    public void run() {
    runService();
    }
    });
    serviceThread.setPriority(Thread.MIN_PRIORITY + 1);
    this.serverEventDispatcher = ServerEventDispatcher.getInstance();
    commandQueue = new LinkedQueue();
    } /*
     * (non-Javadoc)
     * 
     * @see com.counsel.square.server.interfaces.Server#startServer()
     */
    public void startServer() throws IOException {
    if (!isStarted) {
    try {
    Event event = new ServerEvent(this, null, new EventChannelImpl(
    ServerEventDomain.DOMAIN, ServerEventDomain.SERVER_EVENT_START));
    serverEventDispatcher.syncFireOnEventToSequence(event);
    initServer();
    isStarted = true;
    serviceThread.start();
    Event pevent = new ServerEvent(this, null,
    new EventChannelImpl(ServerEventDomain.DOMAIN,
    ServerEventDomain.SERVER_EVENT_POSTSTART));
    serverEventDispatcher.syncFireOnEventToSequence(pevent);
    } catch (Throwable e1) {
    ErrorEventSource source = new ErrorEventSource(this, e1);
    Event event = new ServerEvent(source, null,
    new EventChannelImpl(ServerEventDomain.DOMAIN,
    ServerEventDomain.SERVER_EVENT_ERROR));
    try {
    serverEventDispatcher.asyncFireOnEventToSequence(event);
    } catch (Throwable te) {
    te.printStackTrace();
    }
    }
    }
    } /*
     * (non-Javadoc)
     * 
     * @see com.counsel.square.server.interfaces.Server#stopServer()
     */
    public void stopServer() {
    isStarted = false;
    //to grave.
    String[] info = StackTraceUtils.getCallerInditity();
    if (!"grave".equals(info[1])) {//not called from grave.
    this.grave();
    }
    //fire onStop event here.
    Event event = new ServerEvent(this, null, new EventChannelImpl(ServerEventDomain.DOMAIN,
    ServerEventDomain.SERVER_EVENT_STOP));
    try {
    serverEventDispatcher.syncFireOnEventToSequence(event);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    //serviceThread.interrupt();//or call wakeup method on selector?
    selector.wakeup(); //do clear job here
    clearResource(); //post stop event here.
    Event pevent = new ServerEvent(this, null, new EventChannelImpl(ServerEventDomain.DOMAIN,
    ServerEventDomain.SERVER_EVENT_POSTSTOP));
    try {
    serverEventDispatcher.syncFireOnEventToSequence(pevent);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    } /*
     * (non-Javadoc)
     * 
     * @see com.counsel.square.server.interfaces.Server#getServerName()
     */
    public String getServerName() {
    return this.name;
    } protected void runService() {
    while (isStarted) {
    int i = 0;
    try {
    i = selector.select();
    } catch (Exception ex) {
    //debug
    ex.printStackTrace();
    }
    if (i != 0) {
    Iterator it = selector.selectedKeys().iterator();
    while (it.hasNext()) {
    SelectionKey key = (SelectionKey) it.next();
    it.remove();
    processEvent(key);
    }
    }
    /*
     * //need this? if(serviceThread.isInterrupted() && !isStarted){
     * stop and cast unexecuted commands. break; }
     */
    //do commands here.
    /*
     * (important! the command should not block!!); to avoid block
     * commands,you should never expose server references to an un- safe
     * user code.User's should commit commands through a proxy,such as a
     * KeySpace. or alternately we set a timeout.
     */
    synchronized (commandQueue) {
    Command c = null;
    while (commandQueue.peek() != null) {
    Object command = null;
    try {
    command = commandQueue.take();
    } catch (InterruptedException e) {
    //fire error event
    EventSource source = new ErrorEventSource(this, e);
    Event event = new ServerEvent(source, null,
    new EventChannelImpl(ServerEventDomain.DOMAIN,
    ServerEventDomain.SERVER_EVENT_ERROR));
    try {
    serverEventDispatcher.asyncFireOnEventToFork(event);
    } catch (Throwable t) {
    //should not happen.
    t.printStackTrace();
    }
    }
    if (command != null) {
    try {
    //each command.execute should return within 300ms.
    TimeoutCommandWrap wrap = new TimeoutCommandWrap(
    (Command) command, 300);
    wrap.execute();
    if (wrap.isTimeout()) {
    // TODO do some log here.
    }
    } catch (Throwable ta) {
    EventSource source = new ErrorEventSource(this, ta);
    Event event = new ServerEvent(
    source,
    null,
    new EventChannelImpl(
    ServerEventDomain.DOMAIN,
    ServerEventDomain.SERVER_EVENT_ERROR));
    try {
    serverEventDispatcher
    .asyncFireOnEventToFork(event);
    } catch (Throwable t) {
    //should not happen.
    t.printStackTrace();
    }
    }
    }
    }
    }
    }
    }
      

  4.   

    接上
    private void initServer() throws IOException {
    ssc = ServerSocketChannel.open();
    ssc.configureBlocking(false);
    InetSocketAddress addr = new InetSocketAddress(servicePort);
    ServerSocket socket = ssc.socket();
    socket.bind(addr);
    selector = Selector.open();
    ssc.register(selector, SelectionKey.OP_ACCEPT);
    } private void processEvent(SelectionKey key) {
    try {
    if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {
    Event accept = new ServerEvent(this, null,
    new EventChannelImpl(ServerEventDomain.DOMAIN,
    ServerEventDomain.SERVER_EVENT_ACCEPT));
    serverEventDispatcher.syncFireOnEventToSequence(accept);
    SocketChannel sc = ((ServerSocketChannel) key.channel())
    .accept();
    sc.configureBlocking(false);
    //create a key space for key.
    sc.register(selector, SelectionKey.OP_READ);
    SelectionKey k = sc.keyFor(selector);
    KeySpaceImpl ks = new KeySpaceImpl(k, this);
    k.attach(ks);
    //TODO change this source.should not expose serversocket.
    Event accepted = new ServerEvent(ks, null,
    new EventChannelImpl(ServerEventDomain.DOMAIN,
    ServerEventDomain.SERVER_EVENT_ACCEPTED));
    serverEventDispatcher.syncFireOnEventToSequence(accepted);
    } else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
    KeySpace ks = (KeySpace) key.attachment();
    if (ks.getStatus() != KeySpaceImpl.STATE_READING
    && ks.getStatus() != KeySpaceImpl.STATE_DOWN) {
    ks.setStatus(this, KeySpaceImpl.STATE_READING);
    //perform read task.
    new ServerReadCommand(ks).execute();
    }
    }
    } catch (Throwable re) {//other exception
    EventSource source = new ErrorEventSource(this, re);
    Event event = new ServerEvent(source, null, new EventChannelImpl(
    ServerEventDomain.DOMAIN, ServerEventDomain.SERVER_EVENT_ERROR));
    try {
    serverEventDispatcher.asyncFireOnEventToSequence(event);
    } catch (Throwable ire) {
    ire.printStackTrace();
    }
    }
    } private void clearResource() {
    if (selector.isOpen()) {
    Iterator it = selector.keys().iterator();
    while (it.hasNext()) {
    SelectionKey key = (SelectionKey) it.next();
    if (key.isValid()) {
    try {
    key.channel().close();
    } catch (IOException e1) {
    //ignore.
    }
    }
    }
    try {
    selector.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    if (ssc.isOpen()) {
    try {
    ssc.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    //other clear jobs.
    } /*
     * (non-Javadoc)
     * 
     * @see com.counsel.square.server.interfaces.Finalizable#addFinalizableTask(java.lang.Runnable)
     */
    public void addFinalizableTask(Thread task) {
    Runtime.getRuntime().addShutdownHook(task);
    } /*
     * (non-Javadoc)
     * 
     * @see com.counsel.square.server.interfaces.Finalizable#removeFinalizableTask(java.lang.Thread)
     */
    public void removeFinalizableTask(Thread task) {
    Runtime.getRuntime().removeShutdownHook(task);
    } /*
     * (non-Javadoc)
     * 
     * @see com.counsel.square.server.interfaces.Server#acceptCommand(com.counsel.square.server.interfaces.Command)
     */
    public void acceptCommand(Command command) {
    if (command == null) {
    return;
    }
    synchronized (commandQueue) {
    try {
    commandQueue.put(command);
    } catch (InterruptedException e) {
    EventSource source = new ErrorEventSource(this, e);
    Event event = new ServerEvent(source, null,
    new EventChannelImpl(ServerEventDomain.DOMAIN,
    ServerEventDomain.SERVER_EVENT_ERROR));
    try {
    serverEventDispatcher.asyncFireOnEventToFork(event);
    } catch (Throwable ire) {
    ire.printStackTrace();
    }
    return;
    }
    }
    selector.wakeup();
    } /*
     * (non-Javadoc)
     * 
     * @see com.counsel.square.server.interfaces.LifeCycle#cradleFrom(com.counsel.square.server.interfaces.LifeCycle)
     */
    public void cradleFrom(LifeCycle alive) {
    lcHelper = new LifeCycleHelper(this);
    lcHelper.cradleFrom(alive);
    } /*
     * (non-Javadoc)
     * 
     * @see com.counsel.square.server.interfaces.LifeCycle#grow(com.counsel.square.server.interfaces.LifeCycle)
     */
    public void grow(LifeCycle alive) {
    lcHelper.grow(alive);
    } /*
     * (non-Javadoc)
     * 
     * @see com.counsel.square.server.interfaces.LifeCycle#cutOff(com.counsel.square.server.interfaces.LifeCycle)
     */
    public void cutOff(LifeCycle alive) {
    lcHelper.cutOff(alive);
    } /*
     * (non-Javadoc)
     * 
     * @see com.counsel.square.server.interfaces.LifeCycle#grave()
     */
    public void grave() {
    lcHelper.grave();
    if (this.isStarted) {
    this.stopServer();
    }
    } /*
     * (non-Javadoc)
     * 
     * @see com.counsel.square.server.interfaces.EventSource#dispatcherFor(EventDomain)
     */
    public EventDispatcher dispatcherFor(EventDomain domain) {
    if (ServerEventDomain.DOMAIN.equals(domain)) {
    return serverEventDispatcher;
    } else {
    return lcHelper.dispatcherFor(domain);
    }
    } /*
     * (non-Javadoc)
     * 
     * @see com.counsel.square.server.interfaces.EventListener#handleEvent(com.counsel.square.server.interfaces.Event)
     */
    public void handleEvent(Event event) {
    lcHelper.handleEvent(event);
    } /*
     * (non-Javadoc)
     * 
     * @see com.counsel.square.server.interfaces.EventSource#eventDomains()
     */
    public EventDomain[] eventDomains() {
    return new EventDomain[] { ServerEventDomain.DOMAIN, LifeCycleEventDomain.DOMAIN };
    } /*
     * (non-Javadoc)
     * 
     * @see com.counsel.square.server.interfaces.EventListener#acceptableEventsInSourceDomain(com.counsel.square.server.interfaces.EventDomain)
     */
    public int[] acceptableEventsInSourceDomain(EventDomain sourceDomain) {
    return lcHelper.acceptableEventsInSourceDomain(sourceDomain);
    } /*
     * (non-Javadoc)
     * 
     * @see com.counsel.square.server.interfaces.EventListener#acceptableEventSourceDomains()
     */
    public EventDomain[] acceptableEventSourceDomains() {
    return lcHelper.acceptableEventSourceDomains();
    }
    }
      

  5.   

    一下是一些接口的声明:
     server接口:
    package com.counsel.square.server.interfaces;import java.io.IOException;/**
     * @author 王橙森
     *
     * TODO To change the template for this generated type comment go to
     * Window - Preferences - Java - Code Style - Code Templates
     */
    public interface Server extends Finalizable,LifeCycle {
    public void startServer()throws IOException;
    public void stopServer();
    public String getServerName();
    public void acceptCommand(Command command);
    }
     LifeCycle接口:
    package com.counsel.square.server.interfaces;/**
     * @author 王橙森
     *
     * TODO To change the template for this generated type comment go to
     * Window - Preferences - Java - Code Style - Code Templates
     */
    public interface LifeCycle extends EventSource,EventListener {
    public void cradleFrom(LifeCycle alive);
    public void grow(LifeCycle alive);
    public void cutOff(LifeCycle alive);
    public void grave();
    }EventSource接口:
    package com.counsel.square.server.interfaces;/**
     * @author 王橙森
     *
     * TODO To change the template for this generated type comment go to
     * Window - Preferences - Java - Code Style - Code Templates
     */
    public interface EventSource {
    public EventDomain[] eventDomains();
    public EventDispatcher dispatcherFor(EventDomain domain);
    }
    EventListener接口:
    package com.counsel.square.server.interfaces;/**
     * @author 王橙森
     *
     * TODO To change the template for this generated type comment go to
     * Window - Preferences - Java - Code Style - Code Templates
     */
    public interface EventListener {
    public void handleEvent(Event event);
    public int[] acceptableEventsInSourceDomain(EventDomain sourceDomain);
    public EventDomain[] acceptableEventSourceDomains();
    }
    EventDispatcher接口:
    package com.counsel.square.server.interfaces;import com.counsel.square.server.exceptions.UnSupportedEventListenerException;/**
     * @author 王橙森
     *
     * TODO To change the template for this generated type comment go to
     * Window - Preferences - Java - Code Style - Code Templates
     */
    public interface EventDispatcher {
    public void addListener(EventListener listener)throws InterruptedException;
    public void addListener(EventListener listener , EventChannel channel)throws InterruptedException, UnSupportedEventListenerException;
    public void removeListener(EventListener listener , EventChannel channel)throws InterruptedException;
    public void removeListener(EventListener listener)throws InterruptedException;
    public void syncFireOnEventToSequence(Event event)throws InterruptedException;
    public void asyncFireOnEventToSequence(Event event) throws InterruptedException;
    public void syncFireOnEventToFork(Event event)throws InterruptedException;
    public void asyncFireOnEventToFork(Event event) throws InterruptedException;
    }