public void send(Socket ss,String str)
{
PrintWriter     out=null;
try
{
out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(ss.getOutputStream())));
if(str!=null)
{
out.println(str);
out.flush();
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
/*finally
{
try{
if(out!=null)
    out.close();
   }catch(Exception e){}
    }*/
}
当我把上面代码中 finally部分写上时,程序编译没错,运行一会后报错:socket closed!
不写finally{}运行正常.
问题:
1.不写会不会泄露资源?不是应该调用close()方法吗?
2.关闭out会导致把socket也关掉吗?

解决方案 »

  1.   

    答:
    1)要调用out.close()操作,这是个好习惯。否则可能会“泄漏资源”。
    2)只有当你认为通信全部结束,不需要数据交换时,再去:先关闭流,然后关闭socket.
      

  2.   

    但是实际证明:我关闭out,随之就socket closed!
    上面的send()函数将被其他函数调用,ss在被send()用过后我想在后面继续使用ss;
    不close()泄露资源,调用了又会关闭ss,我将何去何从?out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(ss.getOutputStream())));
    out到底与ss是什么关系?
      

  3.   

    答:“ss在被send()用过后我想在后面继续使用ss”;对于TCP不是重复使用socket,而应重复使用它所关联的
      

  4.   

    现将程序贴下,程序目的:建立一C/S系统,实现当某个client向服务器发消息,服务器将次消息转发给所有的client;当client打下/list字符串时
                           只有本client会获得所有的client的IP,即服务器不向其他人发送。
    以下为服务程序。(不会是我的程序结构设计错了吧,导致我“不close()泄露资源,调用了又会关闭ss”)
    import java.net.*;
    import java.io.*;
    import java.util.LinkedList;public class Server
    {
    ServerSocket ss;
    Socket s;        static LinkedList arrList=new LinkedList(); //用来存储所有连接到服务器的socket(客户) public Server() throws Exception{
    ss=new ServerSocket(2345);

    }
    public static LinkedList getList()
    {
    refresh();
    return arrList;
    }
    public void init() throws Exception{
    while(true){
    s=ss.accept();
    System.out.println("Server listening...");
    arrList.add(s);                    //有刚连接的socket,将之加到arrList
    new MyThread((Socket)s).start();   //为每一个连接到服务器的客户创建一个线程

    }
    public static void refresh()  //更新arrList(去掉断开的连接)
    {
    for(int i=arrList.size();i>0;i--)
    {
    if(((Socket)arrList.get(i-1)).isClosed())
    arrList.remove(i-1);
    }
    }
    public static void main(String[] args) throws Exception
    {
    Server s=new Server();
    s.init();    
    }
    }class MyThread extends Thread{
    Socket s;

    public MyThread(Socket s)  //将刚创建的Socket传到专门处理它的thread
    {
    this.s=s;
    }

    public void run()
    {

    BufferedReader  br=null;
    try{            br =new BufferedReader(new InputStreamReader(s.getInputStream()));
                while(true)
                {
    String temp=br.readLine();
    if(temp.startsWith("/list"))
        ListTheList();
    else
                broadcast("message from "+s.getInetAddress()+":\t"+temp);
        }
         }
        catch(Exception ex)
        {
         ex.printStackTrace();
        }
        finally
    {
    try
    {

    if(br!=null)
    br.close();
    }catch(Exception e){}
        } }
    public void broadcast(String str)
    {
    LinkedList LL=Server.getList();

    for(int i=0;i<LL.size();i++)
    {
    send(((Socket)LL.get(i)),str);
    }

    }
    public void ListTheList()  //列出所有的client
    {
    LinkedList LL=Server.getList();
    StringBuffer sb=new StringBuffer();

    if(LL.size()!=0){
    for(int i=0;i<LL.size();i++)
    {
    sb.append(((Socket)LL.get(i)).getInetAddress()+"is in the list\n");
    }
    send(s,sb.toString());
    }
    }
    public void send(Socket ss,String str)//向连接ss发送 str
    {
    PrintWriter     out=null;
    try
    {
    out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(ss.getOutputStream())));
    if(str!=null)
    {
    out.println(str);
    out.flush();
    }
    }
    catch(Exception ex)
    {
    ex.printStackTrace();
    }
    /*finally
    {
    try{
    if(out!=null)
        out.close();
       }catch(Exception e){}
        }*/
    }
    }
      

  5.   

    那你把流对象作为一个类成员吧,在socket实例化后初始化该对象,到最后认为连接该结束的时候再关闭.
      

  6.   

    答:我的以下意见仅供你参考:
    你的程序的目的,我已清楚.根据这个目的,我认为,你的程序结构在设计时有比较大的不妥,所以才有你的这个问题.
    我想,结构能否如下设计:
    1)每一个客户,对应服务器方的一个线程.也只有这个线程才知道如何与它的客户进行通信.或都说,与这个客户进行通信的信息都委托给这个线程来进行.基于这一个考虑,LinkedList arrList存放的不是Socket对象,而是线程.
    2)每一个线程全权自己管理自己的与它的客户的网络通信,故,当线程创建并启动后,由线程进行网络流的I/O.当通信结束时,由线程进行流的关闭,并关闭它的Socket对象.
    3)每一个线程向外界开放一个方法:send(String msg),用于自己及其它人通过该方法,向本线程的客户发送(或转发)信息.
    4)arrList是一个临界区,至少开放两个方法:一个用于线程将自己加入到arrList中.另一个用于当线程通过结束要关闭之前,将自己从arrLIst中删除.而broadcast(String   str) 功能则用于依次遍历arrList,对其中的每一个线程调用它的send(str)即可.
      

  7.   

    答(继续)而你的原来的设计最大的不好之处是:线程中创建了InputStream流,进行读.而OutputStream流恰恰又在线程之外不断创建与关闭(每转发一次,同一个Socket对象的OutputStream流就要创建与关闭一次),通信结束,Socket对象又在线程之外被不知道被谁关闭.这才是问题的主要根源.以上意见仅供你参考