Socket是TCP/IP协议上的一种通信,在通信的两端各建立一个Socket,从而在通信的两端之间形成网络虚拟链路。一旦建立了虚拟的网络链路,两端的程序就可以通过虚拟链路进行通信。

Client A  发信息给 Client B ,  A的信息首先发送信息到服务器Server ,Server接受到信息后再把A的信息广播发送给所有的Clients

首先我们要在服务器建立一个ServerSocket ,ServerSocket对象用于监听来自客户端的Socket连接,如果没有连接,它将一直处于等待状态。

Socket accept():如果接收到一个客户端Socket的连接请求,该方法将返回一个与客户端Socket对应的Socket

Server示例:

 
1 //创建一个ServerSocket,用于监听客户端Socket的连接请求 

2 ServerSocket ss = new ServerSocket(30000); 

3 //采用循环不断接受来自客户端的请求 

4 while (true){ 

5 //每当接受到客户端Socket的请求,服务器端也对应产生一个Socket 

6 Socket s = ss.accept(); 

7 //下面就可以使用Socket进行通信了 

8 ... 

9 } 
客户端通常可使用Socket的构造器来连接到指定服务器 
Client示例:

 
1 //创建连接到服务器、30000端口的Socket 

2 Socket s = new Socket("192.168.2.214" , 30000); 

3 //下面就可以使用Socket进行通信了 

4 ... 
这样Server和Client就可以进行一个简单的通信了 
当然,我们要做的是多客户,所以每当客户端Socket连接到该ServerSocket之后,程序将对应Socket加入clients集合中保存,并为该Socket启动一条线程,该线程负责处理该Socket所有的通信任务

 
1 //定义保存所有Socket的ArrayList 

2 public static ArrayList<Socket> clients = new ArrayList<Socket>(); 
当服务器线程读到客户端数据之后,程序遍历clients集合,并将该数据向clients集合中的每个Socket发送一次。这样就可以实现一个聊天室的功能了

下面来看看整个功能的demo

先建立一个Java工程,把Server.java运行起来,然后再运行手机模拟器

 

服务器打印信息:

 

程序文件结构:

 

嘿嘿,大家别笑我,我的JAVA水平还是初学者,很多地方都觉得很菜,代码规格程度:小学。 有待提高啊!

1.先看看主Activity : SocketmsgActivity.java

 
001 public class SocketmsgActivity extends Activity {  
002      /** Called when the activity is first created. */ 
003      private SQLiteDatabase db;  
004         
005      Thread thread = null;  
006      Socket s = null;  
007      private InetSocketAddress isa = null;   
008     
009      DataInputStream dis = null;  
010      DataOutputStream dos = null;  
011      private String reMsg=null;  
012      private Boolean isContect = false;  
013      private EditText chattxt;  
014      private EditText chatbox;  
015      private Button chatok;  
016         
017      private String chatKey="SLEEKNETGEOCK4stsjeS";  
018      private String name=null,ip=null,port=null;  
019      @Override 
020      public void onCreate(Bundle savedInstanceState) {  
021          super.onCreate(savedInstanceState);  
022          setContentView(R.layout.main);  
023          chattxt = (EditText)findViewById(R.id.chattxt); 
024          chatbox = (EditText)findViewById(R.id.chatbox);  
025          chatok = (Button)findViewById(R.id.chatOk);  
026          chatbox.setCursorVisible(false);  
027          chatbox.setFocusable(false);  
028          chatbox.setFocusableInTouchMode(false);  
029          chatbox.setGravity(2);  
030             
031          //初始化,创建数据库来储存用户信息  
032          InitDatabase();  
033          db = SQLiteDatabase.openOrCreateDatabase(config.f, null); 
034          try {  
035              Cursor cursor = db.query("config", new String[]{"ip","name","port"},null,null, null, null, null);  
036              while(cursor.moveToNext()){  
037                  name = cursor.getString(cursor.getColumnIndex("name"));  
038                  ip = cursor.getString(cursor.getColumnIndex("ip"));  
039                  port = cursor.getString(cursor.getColumnIndex("port"));  
040              }  
041              cursor.close();  
042          } catch (Exception e) {  
043              // TODO: handle exception  
044              System.out.println(e.toString());  
045          }  
046          db.close();  
047             
048          //设置连接  
049          if(ip==null || port==null){  
050              Intent intent = new Intent(SocketmsgActivity.this,IniActivity.class);  
051              startActivity(intent);  
052              SocketmsgActivity.this.finish();  
053          }  
054          //设置名称  
055          else if(name==null){  
056              Intent intent = new Intent(SocketmsgActivity.this,IniuserActivity.class);  
057              startActivity(intent);  
058              SocketmsgActivity.this.finish();  
059          }else{  
060                 
061              connect();  
062              chatok.setOnClickListener(new View.OnClickListener() {  
063         
064                  @Override 
065                  public void onClick(View v) {  
066         
067                      String str = chattxt.getText().toString().trim();  
068                      System.out.println(s);  
069                      try {  
070                          dos.writeUTF(chatKey+"name:"+name+"end;"+str);  
071                          chattxt.setText("");  
072         
073                      }catch (SocketTimeoutException  e) {  
074                            System.out.println("連接超時,服務器未開啟或IP錯誤");  
075                            Toast.makeText(SocketmsgActivity.this, "連接超時,服務器未開啟或IP錯誤", Toast.LENGTH_SHORT).show(); 
076                            Intent intent = new Intent(SocketmsgActivity.this,IniActivity.class);  
077                          startActivity(intent);  
078                          SocketmsgActivity.this.finish();  
079                            e.printStackTrace();  
080                        } catch (IOException e) {  
081                          // TODO Auto-generated catch block  
082                            System.out.println("連接超時,服務器未開啟或IP錯誤");  
083                            Toast.makeText(SocketmsgActivity.this, "連接超時,服務器未開啟或IP錯誤", Toast.LENGTH_SHORT).show(); 
084                            Intent intent = new Intent(SocketmsgActivity.this,IniActivity.class);  
085                          startActivity(intent);  
086                          SocketmsgActivity.this.finish();  
087                            e.printStackTrace();  
088                      }  
089                  }  
090              });  
091          }  
092      }  
093         
094      private Runnable doThread = new Runnable() {  
095          public void run() {  
096              System.out.println("running!");  
097              ReceiveMsg();  
098          }  
099      };     
100         
101      public void connect() {  
102          try {  
103              s = new Socket();  
104              isa = new InetSocketAddress(ip,Integer.parseInt(port));   
105              s.connect(isa,5000);   
106     
107              if(s.isConnected()){  
108                  dos = new DataOutputStream (s.getOutputStream());  
109                  dis = new DataInputStream (s.getInputStream());  
110                  dos.writeUTF(chatKey+"online:"+name); 
111                  /**  
112                   * 这里是关键,我在此耗时8h+  
113                   * 原因是 子线程不能直接更新UI  
114                   * 为此,我们需要通过Handler物件,通知主线程Ui Thread来更新界面。  
115                   *   
116  */ 
117                  thread = new Thread(null, doThread, "Message");  
118                    thread.start();  
119                    System.out.println("connect");  
120                    isContect=true;  
121              }  
122            }catch (UnknownHostException e) {  
123                System.out.println("連接失敗");  
124              Toast.makeText(SocketmsgActivity.this, "連接失敗", Toast.LENGTH_SHORT).show();  
125              Intent intent = new Intent(SocketmsgActivity.this,IniActivity.class);  
126              startActivity(intent);  
127              SocketmsgActivity.this.finish();  
128                e.printStackTrace();  
129            }catch (SocketTimeoutException  e) {  
130                System.out.println("連接超時,服務器未開啟或IP錯誤");  
131                Toast.makeText(SocketmsgActivity.this, "連接超時,服務器未開啟或IP錯誤", Toast.LENGTH_SHORT).show();  
132              Intent intent = new Intent(SocketmsgActivity.this,IniActivity.class);  
133              startActivity(intent);  
134              SocketmsgActivity.this.finish();  
135                e.printStackTrace();  
136            }catch (IOException e) {  
137                System.out.println("連接失敗");  
138                e.printStackTrace();  
139            }  
140      }  
141        
142      public void disConnect() {  
143          if(dos!=null){  
144          try {  
145                 
146                  dos.writeUTF(chatKey+"offline:"+name); 
147                 
148          } catch (IOException e1) {  
149              // TODO Auto-generated catch block  
150              e1.printStackTrace();  
151          }  
152          try {  
153              s.close();  
154          } catch (IOException e) {  
155                e.printStackTrace();  
156          }  
157          }  
158      }  
159       
160         
161      /**  
162       * 线程监视Server信息  
163  */ 
164      private void ReceiveMsg() {  
165          if (isContect) {  
166              try {  
167                  while ((reMsg = dis.readUTF()) != null) {  
168                      System.out.println(reMsg);  
169                      if (reMsg != null) {  
170     
171                          try {  
172                              Message msgMessage = new Message();  
173                              msgMessage.what = 0x1981;  
174                              handler.sendMessage(msgMessage);  
175                              Thread.sleep(100);  
176                          } catch (InterruptedException e) {  
177                              // TODO Auto-generated catch block  
178                              e.printStackTrace();  
179                          }  
180     
181                      }  
182                  }  
183              } catch (SocketException e) {  
184                  // TODO: handle exception  
185                  System.out.println("exit!");  
186              } catch (IOException e) {  
187                  // TODO Auto-generated catch block  
188                  e.printStackTrace();  
189              }  
190     
191          }  
192      }  
193       
194      /**  
195       * 通过handler更新UI  
196  */ 
197      Handler handler = new Handler() {  
198          public void handleMessage(Message msg) {  
199              switch (msg.what) {  
200              case 0x1981:  
201                  chatbox.setText(chatbox.getText() + reMsg + '\n');  
202                  chatbox.setSelection(chatbox.length());  
203                  break;  
204              }  
205          }  
206      };  
207         
208      @Override 
209      protected void onDestroy() {  
210          // TODO Auto-generated method stub  
211          super.onDestroy();  
212          disConnect();  
213          //System.exit(0);  
214      }  
215         
216      @Override 
217      public boolean onCreateOptionsMenu(Menu menu) {  
218          // TODO Auto-generated method stub  
219          menu.add(0, 1, 1, "初始化設置");  
220          menu.add(0, 2, 2, "退出");  
221          return super.onCreateOptionsMenu(menu);  
222      }  
223     
224      @Override 
225      public boolean onOptionsItemSelected(MenuItem item) {  
226          // TODO Auto-generated method stub  
227          if(item.getItemId()==1){  
228              Intent intent = new Intent(SocketmsgActivity.this,IniActivity.class);  
229              startActivity(intent);  
230              SocketmsgActivity.this.finish();  
231          }else if(item.getItemId()==2){  
232              disConnect();  
233              SocketmsgActivity.this.finish();    
234              android.os.Process.killProcess(android.os.Process.myPid()); 
235              System.exit(0);  
236          }  
237          return super.onOptionsItemSelected(item);  
238      }  
239     
240      public void InitDatabase(){  
241              
242          if(!config.path.exists()){    
243              config.path.mkdirs();      
244              Log.i("LogDemo", "mkdir");    
245          }     
246          if(!config.f.exists()){        
247              try{     
248                  config.f.createNewFile();    
249                  Log.i("LogDemo", "create a new database file");  
250              }catch(IOException e){     
251                  Log.i("LogDemo",e.toString());  
252              }     
253          }    
254          try {  
255              if(tabIsExist("config")==false){  
256                  db = SQLiteDatabase.openOrCreateDatabase(config.f, null);    
257                  db.execSQL("create table config(_id integer primary key autoincrement," +  
258                          "ip varchar(128),port varchar(10),name varchar(32))");  
259                  Log.i("LogDemo", "create a database");  
260                  db.close();  
261              }  
262          } catch (Exception e) {  
263              // TODO: handle exception  
264              Log.i("LogDemo",e.toString());  
265          }  
266      }  
267         
268      /**  
269       * check the database is already exist  
270       * @param tabName  
271       * @return  
272  */ 
273      public boolean tabIsExist(String tabName){  
274          boolean result = false;  
275          if(tabName == null){  
276                  return false;  
277          }  
278          Cursor cursor = null;  
279          db = SQLiteDatabase.openOrCreateDatabase(config.f, null);   
280          try {  
281              String sql = "select count(*) as c from sqlite_master where type ='table' " +  
282                          "and name ='"+tabName.trim()+"' ";  
283              cursor = db.rawQuery(sql, null);  
284              if(cursor.moveToNext()){  
285                  int count = cursor.getInt(0);  
286                  if(count>0){  
287                      result = true;  
288                  }  
289              }  
290                     
291          } catch (Exception e) {  
292                  // TODO: handle exception  
293          }    
294          cursor.close();  
295          db.close();  
296          return result;  
297      }  
298  } 
2.初始化IP和端口Activity, IniActivity.java

 
001 public class IniActivity extends Activity{  
002     
003      private EditText ip,port;  
004      private Button nextButton;  
005      private String getip,getport;  
006      private ProgressDialog progressDialog;  
007      private InetSocketAddress isa = null;   
008      private SQLiteDatabase db;  
009      private String ipstring=null,portString=null;  
010      private int row=0;  
011      @Override 
012      protected void onCreate(Bundle savedInstanceState) {  
013          // TODO Auto-generated method stub  
014          super.onCreate(savedInstanceState);  
015          setContentView(R.layout.config);  
016             
017          ip = (EditText)findViewById(R.id.ip);  
018          port = (EditText)findViewById(R.id.port);  
019          nextButton = (Button)findViewById(R.id.next); 
020             
021             
022          db = SQLiteDatabase.openOrCreateDatabase(config.f, null); 
023          try {  
024              Cursor cursor = db.query("config", new String[]{"ip","port"},null,null, null, null, null);  
025              while(cursor.moveToNext()){  
026                  ipstring = cursor.getString(cursor.getColumnIndex("ip"));  
027                  portString = cursor.getString(cursor.getColumnIndex("port"));  
028                  row++;  
029              }  
030              ip.setText(ipstring);  
031              port.setText(portString);  
032              cursor.close();  
033          } catch (Exception e) {  
034              // TODO: handle exception  
035              System.out.println(e.toString());  
036          }  
037          db.close();  
038             
039          nextButton.setOnClickListener(new nextButtonListenner());  
040      }  
041         
042      class nextButtonListenner implements OnClickListener{  
043     
044          @Override 
045          public void onClick(View v) {  
046              // TODO Auto-generated method stub  
047              getip = ip.getText().toString().trim();  
048              getport = port.getText().toString().trim();  
049              if(getip=="" || getip==null || getip.equals("")){  
050                  Toast.makeText(IniActivity.this, "請輸入IP", Toast.LENGTH_SHORT).show();  
051                  ip.setFocusable(true);  
052              }else if(getport=="" || getport==null || getport.equals("")){  
053                  Toast.makeText(IniActivity.this, "請輸入端口", Toast.LENGTH_SHORT).show();  
054                  port.setFocusable(true);  
055              }else{  
056              //progressDialog = ProgressDialog.show(IniActivity.this, "", "請稍後...", true, false);  
057  //new Thread() {  
058  //@Override  
059  //public void run() {  
060                      try {  
061                          Socket s = new Socket();  
062                          isa = new InetSocketAddress(getip,Integer.parseInt(getport));   
063                          s.connect(isa,5000);   
064                          //showDialog("連接成功",IniActivity.this);  
065                          try {  
066                              //生成ContentValues对象  
067                              ContentValues values = new ContentValues();  
068                              //想该对象当中插入键值对,其中键是列名,值是希望插入到这一列的值,值必须和数据库当中的数据类型一致  
069                              values.put("ip", getip);  
070                              values.put("port",getport);  
071                              db = SQLiteDatabase.openOrCreateDatabase(config.f, null);   
072                              if(row==0){  
073                                  db.insert("config", null, values);  
074                              }else{  
075                                  db.update("config", values ,null,null);  
076                              }  
077                              Toast.makeText(IniActivity.this, "連接成功", Toast.LENGTH_SHORT);  
078                              s.close();  
079                              Intent intent = new Intent(IniActivity.this,IniuserActivity.class);  
080                              startActivity(intent);  
081                              IniActivity.this.finish();  
082                              db.close();  
083                          } catch (Exception e) {  
084                              // TODO: handle exception  
085                              showDialog("設置失敗,數據庫不可用",IniActivity.this);  
086                          }  
087                             
088                             
089                      } catch (UnknownHostException e) {  
090                          // TODO Auto-generated catch block  
091                          e.printStackTrace();  
092                          showDialog("連接失敗,IP或者端口不可用",IniActivity.this);  
093                      }catch (SocketTimeoutException  e) {  
094                            System.out.println("連接超時,服務器未開啟或IP錯誤");  
095                            showDialog("連接超時,服務器未開啟或IP錯誤",IniActivity.this);  
096                            e.printStackTrace();  
097                      }  
098                      catch (IOException e) {  
099                          // TODO Auto-generated catch block  
100                          e.printStackTrace();  
101                          showDialog("連接失敗,IP或者端口不可用",IniActivity.this);  
102                      }  
103                      //progressDialog.dismiss();  
104  //finish();  
105  //}  
106  //}.start();  
107              }  
108                 
109          }  
110             
111      }  
112         
113      /**  
114       * define a dialog for show the message  
115       * @param mess  
116       * @param activity  
117  */ 
118      public void showDialog(String mess,Activity activity){  
119        new AlertDialog.Builder(activity).setTitle("信息")  
120         .setMessage(mess)  
121         .setNegativeButton("確定",new DialogInterface.OnClickListener()  
122         {  
123           public void onClick(DialogInterface dialog, int which)  
124           {            
125           }  
126         })  
127         .show();  
128      }  
129  } 
3.初始化用户名称Activity, IniuserActivity.java

 
01 public class IniuserActivity extends Activity{  
02      private EditText name;  
03      private Button ok;  
04      private SQLiteDatabase db;  
05         
06      private String nameString;  
07      @Override 
08      protected void onCreate(Bundle savedInstanceState) {  
09          // TODO Auto-generated method stub  
10          super.onCreate(savedInstanceState);  
11          setContentView(R.layout.configuser);  
12             
13          name = (EditText)findViewById(R.id.name);  
14          ok = (Button)findViewById(R.id.ok);  
15          ok.setOnClickListener(new okButtonListenner());  
16             
17             
18          db = SQLiteDatabase.openOrCreateDatabase(config.f, null); 
19          try {  
20              Cursor cursor = db.query("config", new String[]{"name"},null,null, null, null, null);  
21              while(cursor.moveToNext()){  
22                  nameString = cursor.getString(cursor.getColumnIndex("name"));  
23              }  
24              name.setText(nameString);  
25              cursor.close();  
26          } catch (Exception e) {  
27              // TODO: handle exception  
28              System.out.println(e.toString());  
29          }  
30          db.close();  
31      }  
32         
33      class okButtonListenner implements OnClickListener{  
34     
35          @Override 
36          public void onClick(View v) {  
37              // TODO Auto-generated method stub  
38              String getname = name.getText().toString().trim();  
39              if(getname==""){  
40                  Toast.makeText(IniuserActivity.this, "請輸入您的稱呢", Toast.LENGTH_SHORT).show();  
41                  name.setFocusable(true);  
42              }else{              
43                  try {  
44                      //生成ContentValues对象  
45                      ContentValues values = new ContentValues();  
46                      //想该对象当中插入键值对,其中键是列名,值是希望插入到这一列的值,值必须和数据库当中的数据类型一致  
47                      values.put("name", getname);  
48                      db = SQLiteDatabase.openOrCreateDatabase(config.f, null);   
49                      db.update("config",values,null,null);  
50                      Toast.makeText(IniuserActivity.this, "設置完成", Toast.LENGTH_SHORT).show();  
51                      Intent intent = new Intent(IniuserActivity.this,SocketmsgActivity.class);  
52                      startActivity(intent);  
53                      IniuserActivity.this.finish();  
54                      db.close();  
55                  } catch (Exception e) {  
56                      // TODO: handle exception  
57                      showDialog("設置失敗,數據庫不可用",IniuserActivity.this);  
58                  }  
59              }  
60          }  
61             
62      }  
63         
64      /**  
65       * define a dialog for show the message  
66       * @param mess  
67       * @param activity  
68  */ 
69      public void showDialog(String mess,Activity activity){  
70        new AlertDialog.Builder(activity).setTitle("信息")  
71         .setMessage(mess)  
72         .setNegativeButton("確定",new DialogInterface.OnClickListener()  
73         {  
74           public void onClick(DialogInterface dialog, int which)  
75           {            
76           }  
77         })  
78         .show();  
79      }  
80  } 
4.config.java

 
1 public class config{  
2     public static String SDCARD = android.os.Environment.getExternalStorageDirectory().getAbsolutePath(); 
3     public static File path = new File(SDCARD+"/RunChatDatabase/"); //数据库文件目录     
4     public static File f = new File(SDCARD+"/RunChatDatabase/config.db"); //数据库文件    
5 } 
布局文件:

1.main.xml

 

print?
01 <?xml version="1.0" encoding="utf-8"?>  
02  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
03      android:orientation="vertical" android:layout_width="fill_parent" 
04      android:layout_height="fill_parent">  
05      <EditText android:id="@+id/chatbox" android:layout_width="fill_parent" 
06          android:layout_height="fill_parent" android:layout_weight="1">  
07      </EditText>  
08      <EditText android:id="@+id/chattxt" android:layout_width="fill_parent" 
09          android:layout_height="wrap_content" android:gravity="top" 
10          android:hint="你想和对方说点什么?">  
11      </EditText>  
12      <Button android:id="@+id/chatOk" android:layout_width="fill_parent" 
13          android:layout_height="wrap_content" android:text="Send"  
14          android:textSize="@dimen/btn1">  
15      </Button>  
16     
17  </LinearLayout> 
2.config.xml

 
print?
01 <?xml version="1.0" encoding="utf-8"?>  
02  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
03      android:orientation="vertical" android:layout_width="fill_parent" 
04      android:layout_height="fill_parent">  
05      <EditText android:id="@+id/chatbox" android:layout_width="fill_parent" 
06          android:layout_height="fill_parent" android:layout_weight="1">  
07      </EditText>  
08      <EditText android:id="@+id/chattxt" android:layout_width="fill_parent" 
09          android:layout_height="wrap_content" android:gravity="top" 
10          android:hint="你想和对方说点什么?">  
11      </EditText>  
12      <Button android:id="@+id/chatOk" android:layout_width="fill_parent" 
13          android:layout_height="wrap_content" android:text="Send"  
14          android:textSize="@dimen/btn1">  
15      </Button>  
16     
17  </LinearLayout> 
3.configuer.xml

 
print?
01 <?xml version="1.0" encoding="utf-8"?>  
02  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
03      android:orientation="vertical" android:layout_width="fill_parent" 
04      android:layout_height="fill_parent">  
05      <EditText android:id="@+id/chatbox" android:layout_width="fill_parent" 
06          android:layout_height="fill_parent" android:layout_weight="1">  
07      </EditText>  
08      <EditText android:id="@+id/chattxt" android:layout_width="fill_parent" 
09          android:layout_height="wrap_content" android:gravity="top" 
10          android:hint="你想和对方说点什么?">  
11      </EditText>  
12      <Button android:id="@+id/chatOk" android:layout_width="fill_parent" 
13          android:layout_height="wrap_content" android:text="Send"  
14          android:textSize="@dimen/btn1">  
15      </Button>  
16     
17  </LinearLayout>

style文件:dimens.xml

 
1 <?xml version="1.0" encoding="utf-8"?>  
2  <resources>       
3      <dimen name="h3">30dip</dimen>   
4      <dimen name="h2">40dip</dimen>   
5      <dimen name="btn1">30dip</dimen>  
6      <dimen name="et1">25dip</dimen>  
7  </resources> 
最后是服务器文件:Server.java

 
001 import java.io.*;  
002  import java.net.*;  
003  import java.text.DateFormat;  
004  import java.text.SimpleDateFormat;  
005  import java.util.*;  
006     
007  import javax.sound.sampled.Port;  
008  import javax.swing.JOptionPane;  
009     
010  public class Server {  
011         
012      ServerSocket ss = null;  
013      private String getnameString=null;  
014      boolean started = false;  
015      List<Client> clients = new ArrayList<Client>();  
016      List<Info> infos = new ArrayList<Info>();  
017      public static void main(String[] args) {  
018          String inputport = JOptionPane.showInputDialog("請輸入該服務器使用的端口:");  
019          int port = Integer.parseInt(inputport);  
020          new Server().start(port);  
021      }  
022      
023      public void start(int port) {  
024          try {  
025             ss = new ServerSocket(port);  
026             System.out.println("服務器啟動");  
027             started = true;  
028          } catch (BindException e) {  
029                System.out.println(" 端口已经被占用");  
030                System.exit(0);  
031             }  
032            catch (IOException e) {  
033               e.printStackTrace();  
034            }  
035     
036        try {  
037           while (started) {  
038               Socket s = ss.accept();  
039               Client c = new Client (s);  
040               System.out.println("a client is connected"); 
041               new Thread(c).start();  
042               clients.add(c);  
043                  
044                  
045           }  
046        } catch (IOException e) {  
047              e.printStackTrace();  
048           }  
049           finally {  
050              try {  
051                 ss.close();  
052              } catch (IOException e) {  
053                    e.printStackTrace();  
054                 }  
055           }  
056     }  
057     public List<Client> getClient(){  
058         return clients;  
059     }  
060     
061    class Client implements Runnable {  
062       private String chatKey="SLEEKNETGEOCK4stsjeS";  
063       private Socket s = null;  
064       private DataInputStream dis = null;  
065       private DataOutputStream dos = null;  
066       private boolean bConnected = false;  
067       private String sendmsg=null;  
068       Client (Socket s) {  
069          this.s = s;  
070          try {  
071            dis = new DataInputStream (s.getInputStream());  
072            dos = new DataOutputStream (s.getOutputStream());  
073            bConnected = true;  
074          } catch(IOException e) {  
075                e.printStackTrace();  
076             }  
077       }  
078          
079       public void send (String str) {  
080              
081           try {  
082               //System.out.println(s);  
083               dos.writeUTF(str+"");  
084               dos.flush();  
085           } catch(IOException e) {  
086               clients.remove(this);  
087               System.out.println("对方已经退出了");  
088           }  
089       }  
090       public void run() {  
091           try {  
092              while (bConnected) {  
093                  String str = dis.readUTF();  
094                  DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");  
095                  String date = "  ["+df.format(new Date())+"]";  
096                  if(str.startsWith(chatKey+"online:")){  
097                      Info info = new Info();  
098                      getnameString = str.substring(27);  
099                         
100                      info.setName(getnameString);  
101                      infos.add(info);  
102                      for (int i=0; i<clients.size(); i++) {  
103                        Client c = clients.get(i);  
104                        c.send(getnameString+" on line."+date);  
105                      }  
106                      System.out.println(getnameString+" on line."+date);  
107                  }else if(str.startsWith(chatKey+"offline:")){  
108                      getnameString = str.substring(28);  
109                      clients.remove(this);  
110                      for (int i=0; i<clients.size(); i++) {  
111                            Client c = clients.get(i);  
112                            c.send(getnameString+" off line."+date);  
113                          }  
114                      System.out.println(getnameString+" off line."+date);  
115                  }  
116                  else{  
117                      int charend = str.indexOf("end;");  
118                      String chatString = str.substring(charend+4);  
119                      String chatName = str.substring(25, charend);  
120                         
121                      sendmsg=chatName+date+"\n"+chatString;   
122                      for (int i=0; i<clients.size(); i++) {  
123                          Client c = clients.get(i);  
124                          c.send(sendmsg);  
125                        }  
126                      System.out.println(sendmsg);  
127                  }  
128               }  
129           } catch (SocketException e) {  
130               System.out.println("client is closed!");  
131               clients.remove(this);  
132           } catch (EOFException e) {  
133                 System.out.println("client is closed!");  
134                 clients.remove(this);  
135              }  
136              catch (IOException e) {  
137                 e.printStackTrace();  
138              }  
139             finally {  
140               try {  
141                 if (dis != null) dis.close();  
142                 if (dos != null) dos.close();  
143                 if (s != null) s.close();  
144               } catch (IOException e) {  
145                     e.printStackTrace();  
146                 }  
147             }  
148       }  
149    }  
150       
151    class Info{  
152        private String info_name = null;  
153        public Info(){  
154               
155        }  
156        public void setName(String name){  
157            info_name = name;  
158        }  
159        public String getName(){  
160            return info_name;  
161        }  
162    }  
163  } 
以上只是一个粗略的聊天室功能,如果要实现私聊,还需要保存该Socket关联的客户信息。一个客户端可以将信息发送另一个指定客户端。实际上,我们知道所有客户端只与服务器连接,客户端之间并没有互相连接。这个功能等我以后有时间再写个demo.....


原文链接:http://www.cnblogs.com/peakzheng/archive/2012/02/0

arrow
arrow
    全站熱搜

    戮克 發表在 痞客邦 留言(0) 人氣()