ChatServer(21)

/**

*Title:ChatServer
*Description:1、这里的改进方法是将接收端和数据端分开。从而避免了当一个客户端连上以后,因为已经用过accept(),
                              进入dis.readUTF();循环而不能接收其他的客户端的情况。
                        2、运用多线程的方法打开多个客户端。
*@Copyright:
*@Company:
*@autor:firefly
*@version:1.0
*@time:2012.10.3
*/
import java.io.*;
import java.net.*;
import java.util.*;

public class ChatServer { 
 boolean started = false;
 ServerSocket ss = null;
 
 List<Client> clients = new ArrayList<Client>();
 
 public static void main(String[] args) {
  new ChatServer().start();
 }
 
 public void start() {  //start是里面的东西是动态的,不能写在的下静态的main里面,所以单独构造一个start方法,
                             //而在main里面也只不过是调用 ,这也更符合面向对象的特点。
  try {  //这里用trycatch单独对ServerSocket进行捕获,单独处理和下面的trycatch分开,会更好一点。
   ss = new ServerSocket(8888); //基于TCP的服务,先把服务起来. 创建绑定到特定端口的服务器套接字.
   started = true;
  } catch (BindException e){   //绑定异常,它是runtime异常可以不捕获,如果能加上这个细节就更好了。
   System.out.println("端口正在使用中……");
   System.out.println("请关闭相关的程序并重新运行服务器。");
   System.exit(0); //如果启动两个ChatServer会出现NullPointerException,可以给出上面的提示,并退出程序。
  }catch (IOException e) {
   e.printStackTrace();
  }
  
  try {
   while(started) {
    Socket s = ss.accept();  //侦听并接受到此套接字的连接。
    Client c = new Client(s);
    new Thread(c).start();
    clients.add(c);
   }
  } catch (IOException e) {
   e.printStackTrace();
  } finally {
   try {
    ss.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
  
 }
 
 public class Client implements Runnable {
  private Socket s = null;
  private DataInputStream dis = null;
  private DataOutputStream dos = null;
  private boolean cConnected = false;
  
  public Client(Socket s) {
   this.s = s;
   try {
    dis = new DataInputStream(s.getInputStream());
    dos = new DataOutputStream(s.getOutputStream());
    cConnected = true;
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
  
  public void send (String str) {
   try {
    dos.writeUTF(str);
   } catch (IOException e) {
    clients.remove(this);    //当出现异常的时候说明已经有客户端关闭,这时执行此操作把当前的对象从List中删除。
    System.out.println("对方退出了!我从List中去掉了。");
   }
  }
  
  public void run() {
   System.out.println("a client connected!");
   try {
    while (cConnected) {
     String str = dis.readUTF();
     //如果把chatClient的客户端关了之后chatServer会出现java.io.EOFException.(end of file);
     //所以在Client端关了之后,紧接着也要把ChatServer这里的Socket和InputStream也要关了。
System.out.println(str);
     for(int i = 0; i<clients.size(); i++) {
      Client c = clients.get(i);
      c.send(str);
     }
     /*   //也可以用这种for循环的表示方法。但他的内部进行锁定效率不会很高。
      for(Iterator<Client> it = clients.Iterator(); it.hasNext(); ) {
       Client c = it.hasNext();
       c.send(str);
      }
     */
    }
   }  catch(EOFException e) {
    System.out.println("client closed!"); // 在抛出异常后,给一些比较友好的提示.
   } catch (IOException e) {
    e.printStackTrace();
   } finally {
    try {
     if(dis != null) dis.close();
     if(dos != null) dos.close();
     if(s != null) s.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
  }
  
 }
 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值