我在写一个服务器,请看最下方代码。
添加重启功能时需要结束这个线程,可是如何结束呢?!!!
线程一直在执行socket = serverSocket.accept()interrupt()方法丝毫不起作用,我搞不懂这个方法是干嘛用的。新手所以
大侠们多多指教!package com.socket;
import java.net.*;
/**
 *
 * @author XHF
 */
public class PrinterServer extends Thread{
 
    /** Creates a new instance of PrinterServer */                                
    int port = 8888;                                  //默认服务器端口
    ServerSocket serverSocket = null;
    public PrinterServer() {                    
        try {
            serverSocket  = new ServerSocket(port);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    public PrinterServer(int port){
       
        try {
             if(port!=0){
                 this.port = port;
             }
            serverSocket  = new ServerSocket(port);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    public void run(){
        try {
            while(true){
                Socket socket = null;
                socket = serverSocket.accept();
                this.threadNum++;
                UserThread userThread = new UserThread(socket);          //!!!!!!!!!!!!!!!!!
                userThread.start();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
  }

解决方案 »

  1.   

    此回复为自动发出,仅用于显示而已,并无任何其他特殊作用
    楼主【xhf1234】截止到2008-07-19 19:56:10的历史汇总数据(不包括此帖):
    发帖的总数量:15                       发帖的总分数:890                      每贴平均分数:59                       
    回帖的总数量:17                       得分贴总数量:0                        回帖的得分率:0%                       
    结贴的总数量:15                       结贴的总分数:890                      
    无满意结贴数:0                        无满意结贴分:0                        
    未结的帖子数:0                        未结的总分数:0                        
    结贴的百分比:100.00%               结分的百分比:100.00%                  
    无满意结贴率:0.00  %               无满意结分率:0.00  %                  
    敬礼!
      

  2.   

    我写的代码是在socket = serverSocket.accept();  这阻塞了
    interrupt()会在这抛出异常,所以我改成:
            try { 
                while(true){ 
                    Socket socket = null; 
                    socket = serverSocket.accept(); 
                    this.threadNum++; 
                    UserThread userThread = new UserThread(socket);        
                    userThread.start(); 
                } 
            } catch (Exception ex) { 
                return;                               //这改了
            } 可还是没用
      

  3.   

    不要写成while(true)可以增加一个成员变量:
    boolean isStop;重启时,令isStop=true;   try { 
                while(!isStop){ 
                    Socket socket = null; 
                    socket = serverSocket.accept(); 
                    this.threadNum++; 
                    UserThread userThread = new UserThread(socket);        
                    userThread.start(); 
                } 
            } catch (Exception ex) { 
                return;                              //这改了 
            } 所以你可以定义一个stopService()方法,在这个方法里令isStop=true;
    这样 socket = serverSocket.accept();这句代码不会被执行到,下面的线程也不会开始执行了。
      

  4.   

    这方法行不通的
    因为我这种情况属于无限循环内的阻塞,线程执行到socket = serverSocket.accept(); 停住了,只有accept()方法返回时才向下执行,所以就算在阻塞过程种把while(!isStop)中的isStop为置true也没用,线程根本走不到这一步
      

  5.   

    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.net.SocketTimeoutException;
    /**
     * @author XHF
     */
    public class PrinterServer extends Thread { //** Creates a new instance of PrinterServer */
    //文档注释一般加到常量、方法或类的前面,用以说明其使用方法,例如:
    /** 服务器默认端口号 */
    public static final int DEFAULT_PORT = 8888; //int port = 8888;  //默认服务器端口
    //ServerSocket serverSocket = null; //实例域如无特殊要求一般声明成私有的
    private int port;  //默认值的定义放常量中更好
    private ServerSocket serverSocket;  //引用类型实例域默认值就是 null public PrinterServer() {
    this(DEFAULT_PORT);  //以默认服务器端口号为参数调用另一构造方法就行
    //try {
    // serverSocket = new ServerSocket(port);
    //} catch (Exception ex) {
    // ex.printStackTrace();
    //}
    } public PrinterServer(int port) {
    try {
    if (port <= 0 || port > 0xFFFF) {  //if (port != 0) {
    this.port = DEFAULT_PORT;  //如果端口号超出取值范围就使用默认端口号
    } else {
    this.port = port;
    }
    this.serverSocket = new ServerSocket(port);
    //设置超时值如果 accept 方法调用超过超时值将引发 java.net.SocketTimeoutException
    this.serverSocket.setSoTimeout(3000);
    } catch (IOException /*Exception*/ ex) {  //异常捕获要精细一点
    ex.printStackTrace();
    }
    } private volatile boolean running;  //服务器正在运行的标志 public synchronized void startServer() {  //启动服务器
    this.running = true;
    start();  //启动服务器线程
    } public synchronized void stopServer() {
    this.running = false;  //通过此方法将标志变量设置成 false 来停掉服务器
    } public void run() {
    try {
    while (this.running) {  //while (true) {
    Socket socket = null;
    try {
    socket = this.serverSocket.accept();
    } catch (SocketTimeoutException e) {
    e.printStackTrace();
    }
    if (socket != null) {  //防止因超时未获取到 Socket 而出现 NullPointerException
    //this.threadNum++;
    //UserThread userThread = new UserThread(socket);
    //!!!!!!!!!!!!!!!!!
    //userThread.start();
    }
    }
    } catch (IOException e) {
    e.printStackTrace();
    }
    }}
      

  6.   

    interrupt() 方法调用之后只是给线程设置了一个“中断标志”,它并不能真正的终止线程执行。
      

  7.   


    光这样不行,accept 方法一样会被阻塞在那儿,直到连接请求到来。
      

  8.   

    非常非常感谢sagezk
    一向都非常认真的解答新手的问题
    好人有好报(*^__^*)
      

  9.   

    可这样的话每个3秒钟会打印一条异常信息,觉得不舒服
    去掉e.printStackTrace();可以吧?
      

  10.   

    另外:最好通过实现 Runnable 接口来实现多线程操作,相比继承自 Thread 类这样更灵活。
      

  11.   

    按照你的方法成功了
    可还有个问题,下边是我写的重启服务器的方法  
    public static void restart(){
             server.stopServer();
             f.dispose();
            try {
                Thread.sleep(3000);           //可是在这里无论主线程休眠多长时间,重启的时候都会
            } catch (InterruptedException ex) {    //抛出端口被占用的异常,就是说原来那个还没有完全停止
                ex.printStackTrace();
            }
             f=new ManageFrame();
             f.setVisible(true);         
             server = new PrinterServer();
             server.startServer();  
         }
    }
    这是什么问题呢?怎么解决?
    有一个问题我不大懂。就是ServerSocket这个线程被停止后,它之前创建的若干个UserThread线程是不是也自动停止了?还是得写出停止当前所有线程的代码?如果要的话该怎么写?
      

  12.   

    那为什么还要Thread呢?  两者有什么应用上的区别吗?比如哪个用于哪种情况较好
      

  13.   

    只有accept()方法返回时才向下执行
    解决方法很简单。
    让你的停止服务器的程序,链接一下那个端口啊!,哈哈哈!做一个虚假的链接,主程序就继续运行了,也就可以判断你所谓的是否停止的标记了。这个方法可以用来远程关闭服务
      

  14.   

    我改成如下:   可还是不行。
        public synchronized void stopServer() {
            this.running = false;
            Socket socket = null;
            try {
                socket = new Socket("127.0.0.1",port);
            } catch (UnknownHostException ex) {
                ex.printStackTrace();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            try {
                socket.getOutputStream().write(1);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            try {
                socket.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    总的代码:
      1、
      2.ServerSocket:
       /*
     * UserThread.java
     *
     * Created on 2008年7月18日, 上午1:25
     *
     * To change this template, choose Tools | Template Manager
     * and open the template in the editor.
     */package com.socket;
    import com.Main;
    import java.io.*;
    import java.net.*;
    /**
     *
     * @author XHF
     */
    public class UserThread extends Thread{
        protected DataInputStream inputStream;
        protected DataOutputStream outputStream;
        protected Socket socket;
        protected boolean running;
        /** Creates a new instance of UserThread */
        public UserThread(Socket socket) {
          
            try {
                this.socket = socket;
                inputStream = new DataInputStream(socket.getInputStream());
                outputStream = new DataOutputStream(socket.getOutputStream());
                this.socket.setSoTimeout(30000);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
           
        }
        public synchronized void startThread() {  
            this.running = true;
            start();  
        }
         public synchronized void stopThread() {
            this.running = false;  
        }
        public void run(){
            String str = null;
            try {
          
                str = inputStream.readUTF();
           
                boolean b = this.login(str);
                if(b==false)
                    return;
                while(running){
                      try {
                          str = inputStream.readUTF();
                      } catch (SocketTimeoutException e) {
               
                      }
           
                }
                } catch (IOException ex) {
                ex.printStackTrace();
           }
           
            
        }
        public boolean login(String str){
         
                String[] s = str.split(",");
                String id = s[0];
                String pw = s[1];
                boolean b =Main.login(id,pw);
                if(b==true){                         //帐号密码正确
                    try {
                    outputStream.writeUTF("a");               //返回信息给客户端a:成功,b:失败
                    return true;
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                }
                else{                                  //帐号密码错误
                try {
                    outputStream.writeUTF("b");
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                try {
                    
                    socket.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                    return false;
                }
         return false;
        }
    }
      

  15.   

    不好意思 发错了
    总的代码:
    /*
     * PrinterServer.java
     *
     * Created on 2008年7月18日, 上午1:07
     *
     * To change this template, choose Tools | Template Manager
     * and open the template in the editor.
     */
    package com.socket;
    import java.io.IOException;
    import java.net.*;
    /**
     *
     * @author XHF
     */
    public class PrinterServer extends Thread{
     
        /** Creates a new instance of PrinterServer */
        
        //默认端口号
        public static final int DEFFAULT_PORT = 8888;                                
                               
        private ServerSocket serverSocket;
        private int port;
        
        private volatile boolean running;  //服务器正在运行的标志
        
        public PrinterServer() {                       
            this(DEFFAULT_PORT);
        }
        public PrinterServer(int port){
           
            try {
                 if(port <= 0 || port > 0xFFFF){
                     this.port = port;
                 }
                serverSocket  = new ServerSocket(port);
                //设置超时值如果 accept 方法调用超过超时值将引发 java.net.SocketTimeoutException
       //          this.serverSocket.setSoTimeout(3000);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        public synchronized void startServer() {  //启动服务器
            this.running = true;
            start();  //启动服务器线程
        }
        public synchronized void stopServer() {
            this.running = false;
            Socket socket = null;
            try {
                socket = new Socket("127.0.0.1",port);
            } catch (UnknownHostException ex) {
                ex.printStackTrace();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            try {
                socket.getOutputStream().write(1);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            try {
                socket.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        public void run(){
             try {
                 while(this.running){
                     Socket socket = null;
                     try {              
                         socket = serverSocket.accept();      
                     } catch (SocketTimeoutException e) {                
                         //e.printStackTrace();
                     }
                     if(socket!=null){
                          UserThread userThread = new UserThread(socket);
                          userThread.start();
                     }
                }
            } catch (IOException ex) {
                        ex.printStackTrace();
            }
        }
    }
      

  16.   

    你可以在停止ServerSocket前发送一个停止标志给客户端,客户端接收到这个标志后就停止退出,而你的服务器的每个客户线程也有个运行标志,当ServerSocket停止,这个标志就变为false,这样这个
    线程就会自动跳出的啦。。同理,如果客户端要退出,则也发一个停止标志给服务器,服务器收到这个标志,就断开相应的客户服务。
      

  17.   

    这样不安全。因为这种方法只有在客户端程序正常运行正常关闭的时候起作用。如果客户端非正常关闭程序呢?比如说基地DOWN掉了什么的,那就不回给服务器端发送信息的。
    我想要一个主动的方法,而不是被动的
      

  18.   

    问题解决了,但是有个小问题
    为什么我用socket = new Socket("127.0.0.1",port);报错了,原因是端口为0,可是我的ServerSocket构造函数中已经赋值port=8888了啊,为什么?????????
    一定要socket = new Socket("127.0.0.1",8888);  ??? 大侠们指导一下为什么?
    代码如下:
    /*
     * PrinterServer.java
     *
     * Created on 2008年7月18日, 上午1:07
     *
     * To change this template, choose Tools | Template Manager
     * and open the template in the editor.
     */
    package com.socket;
    import java.io.IOException;
    import java.net.*;
    /**
     *
     * @author XHF
     */
    public class PrinterServer extends Thread{
     
        /** Creates a new instance of PrinterServer */
        
        //默认端口号
        public static final int DEFFAULT_PORT = 8888;                                
                               
        private ServerSocket serverSocket;
        private int port;
        
        private volatile boolean running;  //服务器正在运行的标志
        
        public PrinterServer() {                       
            this(DEFFAULT_PORT);
        }
        public PrinterServer(int port){
           
            try {
                 if(port <= 0 || port > 0xFFFF){
                     this.port = port;
                 }
                serverSocket  = new ServerSocket(port);
                //设置超时值如果 accept 方法调用超过超时值将引发 java.net.SocketTimeoutException
       //          this.serverSocket.setSoTimeout(3000);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        public synchronized void startServer() {  //启动服务器
            this.running = true;
            start();  //启动服务器线程
        }
        public synchronized void stopServer() {
            this.running = false;
            try {
                this.serverSocket.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            //用socket虚假连接,跳过阻塞,结束进程
            Socket socket = null;
            try {
                socket = new Socket("127.0.0.1",8888);      //!!!!!!!!!!!
            } catch (UnknownHostException ex) {
                ex.printStackTrace();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            try {
                socket.getOutputStream().write(1);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            try {
                socket.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            
        }
        public void run(){
             try {
                 while(this.running){
                     Socket socket = null;
                     try {              
                         socket = serverSocket.accept();      
                     } catch (SocketTimeoutException e) {                
                         //e.printStackTrace();
                     }
                     if(socket!=null){
                          UserThread userThread = new UserThread(socket);
                          userThread.start();
                     }
                }
            } catch (IOException ex) {
                        System.out.println("The serverSocket stopping");
            }
        }
    }
      

  19.   

    那得看你是如何调用 stopServer 了!,我想你应该换一下思路了。    //默认端口号
        public static final int DEFFAULT_PORT = 8888;                               
                             
        private ServerSocket serverSocket;
        private int port =DEFFAULT_PORT ;  // 我不懂你为何不这样写呢?非得跟自己过不去。
      

  20.   

    socket = new Socket("127.0.0.1",8888);      //!!!!!!!!!!! 将这句改成:socket = new Socket("127.0.0.1", this.port);
      

  21.   

    我一开始也是这么写,奇怪的是报错了。调试的时候发现port=0   不知道为什么????????
      

  22.   

    如果线程在这样的语句阻塞了:str = inputStream.readUTF();
    怎么跳过呢?用socket.setSoTimeout(3000); 好像不管用了
      

  23.   

    lz这问题太easy了。最近刚好也写了一个这样的程序。首先解决你停止socketserver的方法:其实5楼的朋友说对了一半,你需要一个while。但是你还应该增加一句:this.serverSocket.setSoTimeout(6000);你设置为超时后,它就不会一直停留在accept()处了。
    第二个问题:线程停止的问题,建议你最好使用线程池,关闭线程池时,系统有提供函数,第一步阻塞添加新的线程,第二步等待所有线程执行完成。所以,有了线程池后,你的线程就会安全一点。
      

  24.   

    哦,补充一下,如果你没太明白的话,我这有段代码,可以发你看看,发邮件给我吧:[email protected]
      

  25.   

    也可以利用多线程来实现,在另个线程中将socket关闭,accept方法就会抛出异常,在此捕获退出。
      

  26.   

    1、使用子线程启动 socket
    2、设置超时,server.setSoTimeout(3000); 这样server.accept 会3秒钟返回,而不是一直阻塞。
    3、在想关闭server的时候设置  runServer=false/**
     * 启动socket服务
     */
    private void startSocketServer() {

    runServer = true;
    new Thread() {
    public void run(){
    startSocketServer(SERVERPORT);
    beginServerSocketListen();
    }
    }.start();

    }/**
     * 开启监听,循环接受客户端发送的消息
     */
    public void beginServerSocketListen() {

    System.out.println(" controlPlayerUIApplication socket Server is Running ....");

    while (runServer) {

    System.out.println("beginServerSocketListen-------running=="+runServer);
    Socket socket = null;

    try {

    server.setSoTimeout(3000);
    socket = server.accept();

    BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); String receiveMSG = in.readLine();
    System.out.println(" ControlPlayerUIApplication RECEIVE MESSAGE:|" + receiveMSG + "|---------");
    in.close();
    } catch (IOException e) {
    //e.printStackTrace();
    } finally {

    try {
    if(socket != null) {
    socket.close();
    }
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

    }
    }