簡單的聊天程式,主要用到的是Socket

huidaoli發表於2013-08-12

服務端:

  1 import java.io.*;
  2 
  3 import java.net.*;
  4 
  5 import java.util.*;
  6 
  7 public class ChatServer {
  8 
  9 boolean stat = false;
 10 
 11 ServerSocket ss = null;
 12 
 13 List<Client> clients = new ArrayList<Client>();//用於存客戶端
 14 
 15 public static void main(String[] args) {
 16 
 17   new ChatServer().start();
 18 
 19 }
 20 
 21 public void start(){
 22 
 23   try {
 24 
 25    ss = new ServerSocket(8888);
 26 
 27    stat = true;
 28 
 29   } catch(BindException e){  //Sever端已經執行,當重複執行時拋異常
 30 
 31    System.out.println("埠正在使用中。。。。");
 32 
 33    System.out.println("請關掉相關程式並重新執行伺服器!"); //還會拋別的異常,所以直接關閉視窗
 34 
 35    System.exit(0);
 36 
 37   } catch(IOException e) {
 38 
 39    e.printStackTrace();
 40 
 41   }
 42 
 43   try{
 44 
 45    while(stat){
 46 
 47     Socket s = ss.accept();
 48 
 49 System.out.println("a client connected!" );  //測試語句寫在最左邊,以後沒用可以刪除或注掉
 50 
 51     Client c = new Client(s);    //每建立一個客戶端,就new一個客戶端物件,啟動一個執行緒
 52 
 53     new Thread(c).start();
 54 
 55     clients.add(c);  //勿忘寫,將每個客戶端加入到容器裡
 56 
 57    }
 58 
 59   } catch (IOException e) {
 60 
 61    e.printStackTrace();
 62 
 63   } finally {
 64 
 65    try {
 66 
 67     ss.close();
 68 
 69    } catch (IOException e) {
 70 
 71     e.printStackTrace();
 72 
 73    }
 74 
 75   }
 76 
 77 }
 78 
 79 class Client implements Runnable {
 80 
 81   private Socket s;
 82 
 83   private DataInputStream dis;
 84 
 85   private DataOutputStream dos;
 86 
 87   private boolean cont = false;
 88 
 89   public Client(Socket s){
 90 
 91    this.s = s; 
 92 
 93    try {
 94 
 95     dis = new DataInputStream(s.getInputStream());//初始化
 96 
 97     dos = new DataOutputStream(s.getOutputStream());
 98 
 99     cont = true;
100 
101    } catch (IOException e) {
102 
103     e.printStackTrace();
104 
105    }
106 
107   }
108 
109   public void send(String str){  //用於傳送給客戶端
110 
111    try {
112 
113     dos.writeUTF(str);
114 
115    } catch (IOException e) {
116 
117     clients.remove(this);  //移除那個退出的物件
118 
119     System.out.println("一個客戶退出了");
120 
121     //e.printStackTrace();
122 
123    }
124 
125   }
126 
127   public void run() {
128 
129    try{
130 
131     while(cont){
132 
133      String str = dis.readUTF(); //阻塞式方法
134 
135 System.out.println(str);
136 
137      for(int i=0; i<clients.size(); i++){
138 
139       Client c = clients.get(i);  //取客戶端
140 
141       c.send(str); 
142 
143      }
144 
145      /*     另外兩種方法,但不適用,它會鎖定服務端
146 
147      for(Iterator<Client> it = clients.iterator(); it.hasNext();){
148 
149       Client c = it.next();
150 
151       c.send(str);
152 
153      }
154 
155      Iterator<Client> it = clients.iterator();
156 
157      while(it.hasNext()){
158 
159       Client c = it.next();
160 
161       c.send(str);
162 
163      }
164 
165      */
166 
167     }
168 
169    } catch (EOFException e){   //readUTF()阻塞式方法,所以關閉客戶端會拋異常
170 
171     System.out.println("Client closed!");
172 
173    } catch (IOException e) {
174 
175     e.printStackTrace();
176 
177    } finally {
178 
179     try {
180 
181      if(dis != null) dis.close();
182 
183      if(dos != null) dos.close();
184 
185      if(s != null) {
186 
187       s.close();
188 
189       s = null;//更嚴格的方法,等於空就沒人去用了,垃圾收集器就回收走
190 
191      }
192 
193     } catch (IOException e) {
194 
195      e.printStackTrace();
196 
197     }
198 
199    }
200 
201   }
202 
203 }
204 
205 }

 

客戶端:

import java.awt.*;

import java.awt.event.*;

import java.io.*;

import java.net.*;

public class ChatClient extends Frame {

Socket s = null;

DataOutputStream dos = null;

DataInputStream dis = null;

private boolean cont = false;

TextField tfTxt = new TextField();

TextArea taContent = new TextArea();

Thread tRecv = new Thread(new RecvThread());

public static void main(String[] args) {

  new ChatClient().launchFrame();

}

public void launchFrame() {

  setLocation(400, 300);

  this.setSize(300, 300);

  add(tfTxt,BorderLayout.SOUTH);

  add(taContent,BorderLayout.NORTH);

  pack(); //包在一起,去掉中間空著的

  this.addWindowListener(new WindowAdapter(){

   public void windowClosing(WindowEvent e){

    disconnect();

    System.exit(0);

   }

  });

  tfTxt.addActionListener(new TfListent());

  setVisible(true);

  connect();

  tRecv.start();   //啟動執行緒

}

public void connect(){

  try {

   s = new Socket("127.0.0.1",8888);//注意不要定義成Socket s,這就成了區域性變數而不是成員變數了

System.out.println("connected!");

   dos = new DataOutputStream(s.getOutputStream());

   dis = new DataInputStream(s.getInputStream());

   cont = true;

  } catch (UnknownHostException e) {

   e.printStackTrace();

  } catch (IOException e) {

   e.printStackTrace();

  }

}

public void disconnect(){

  try {

   dos.close();

   dis.close();

   s.close();

  } catch (IOException e) {

   e.printStackTrace();

  }

  /*//無法解決readUTF阻塞式方法

  try {

   cont = false;  //關閉執行緒

   tRecv.join();  //合併執行緒,徹底讓他停止

  } catch (InterruptedException  e) {

   e.printStackTrace();

  } finally {

   try {

    dos.close(); //執行緒停止之後才能關流,不然拋SocketException異常

    dis.close();

    s.close();

   } catch (IOException e) {

    e.printStackTrace();

   }

  }

  */

}

private class TfListent implements ActionListener {

  public void actionPerformed(ActionEvent e) {

   String str = tfTxt.getText().trim();

   tfTxt.setText("");

   try {

    dos.writeUTF(str);

    dos.flush();

   } catch (IOException e1) {

    e1.printStackTrace();

   }

  }

}

private class RecvThread implements Runnable{

  public void run() {

   try {

    while(cont){

     String str = dis.readUTF();

     taContent.setText(taContent.getText() + str + '\n');

    }

   } catch (SocketException e){

    System.out.println("退出了,bye!");

   } catch (IOException e) {  

    e.printStackTrace();

   }

  }

}

}

 

簡單的聊天程式,主要用到的是Socket,執行緒以及流

如果沒看懂可以去我部落格

http://www.cnblogs.com/huidaoli/p/3252924.html

相關文章