zoukankan      html  css  js  c++  java
  • Android 基于Socket的聊天室

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

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

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

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

    Server示例:

    复制代码
    //创建一个ServerSocket,用于监听客户端Socket的连接请求
    ServerSocket ss = new ServerSocket(30000);
    //采用循环不断接受来自客户端的请求
    while (true){
    //每当接受到客户端Socket的请求,服务器端也对应产生一个Socket
    Socket s = ss.accept();
    //下面就可以使用Socket进行通信了
    ...
    }
    复制代码

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

    //创建连接到服务器、30000端口的Socket
    Socket s = new Socket("192.168.2.214" , 30000);
    //下面就可以使用Socket进行通信了
    ...


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

    //定义保存所有Socket的ArrayList
    public static ArrayList<Socket> clients = new ArrayList<Socket>();

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

    下面来看看整个功能的demo

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

    服务器打印信息:

    程序文件结构:


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

    1.先看看主Activity : SocketmsgActivity.java

    SocketmsgActivity.java 
     public class SocketmsgActivity extends Activity {
         /** Called when the activity is first created. */
         private SQLiteDatabase db;
         
         Thread thread = null;
         Socket s = null;
         private InetSocketAddress isa = null; 
     
         DataInputStream dis = null;
         DataOutputStream dos = null;
         private String reMsg=null;
         private Boolean isContect = false;
         private EditText chattxt;
         private EditText chatbox;
         private Button chatok;
         
         private String chatKey="SLEEKNETGEOCK4stsjeS";
         private String name=null,ip=null,port=null;
         @Override
         public void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
             setContentView(R.layout.main);
             chattxt = (EditText)findViewById(R.id.chattxt);
             chatbox = (EditText)findViewById(R.id.chatbox);
             chatok = (Button)findViewById(R.id.chatOk);
             chatbox.setCursorVisible(false);
             chatbox.setFocusable(false);
             chatbox.setFocusableInTouchMode(false);
             chatbox.setGravity(2);
             
             //初始化,创建数据库来储存用户信息
             InitDatabase();
             db = SQLiteDatabase.openOrCreateDatabase(config.f, null);
             try {
                 Cursor cursor = db.query("config", new String[]{"ip","name","port"},null,null, null, null, null);
                 while(cursor.moveToNext()){
                     name = cursor.getString(cursor.getColumnIndex("name"));
                     ip = cursor.getString(cursor.getColumnIndex("ip"));
                     port = cursor.getString(cursor.getColumnIndex("port"));
                 }
                 cursor.close();
             } catch (Exception e) {
                 // TODO: handle exception
                 System.out.println(e.toString());
             }
             db.close();
             
             //设置连接
             if(ip==null || port==null){
                 Intent intent = new Intent(SocketmsgActivity.this,IniActivity.class);
                 startActivity(intent);
                 SocketmsgActivity.this.finish();
             }
             //设置名称
             else if(name==null){
                 Intent intent = new Intent(SocketmsgActivity.this,IniuserActivity.class);
                 startActivity(intent);
                 SocketmsgActivity.this.finish();
             }else{
                 
                 connect();
                 chatok.setOnClickListener(new View.OnClickListener() {
         
                     @Override
                     public void onClick(View v) {
         
                         String str = chattxt.getText().toString().trim();
                         System.out.println(s);
                         try {
                             dos.writeUTF(chatKey+"name:"+name+"end;"+str);
                             chattxt.setText("");
         
                         }catch (SocketTimeoutException  e) {
                               System.out.println("連接超時,服務器未開啟或IP錯誤");
                               Toast.makeText(SocketmsgActivity.this, "連接超時,服務器未開啟或IP錯誤", Toast.LENGTH_SHORT).show();
                               Intent intent = new Intent(SocketmsgActivity.this,IniActivity.class);
                             startActivity(intent);
                             SocketmsgActivity.this.finish();
                               e.printStackTrace();
                           } catch (IOException e) {
                             // TODO Auto-generated catch block
                               System.out.println("連接超時,服務器未開啟或IP錯誤");
                               Toast.makeText(SocketmsgActivity.this, "連接超時,服務器未開啟或IP錯誤", Toast.LENGTH_SHORT).show();
                               Intent intent = new Intent(SocketmsgActivity.this,IniActivity.class);
                             startActivity(intent);
                             SocketmsgActivity.this.finish();
                               e.printStackTrace();
                         }
                     }
                 });
             }
         }
         
         private Runnable doThread = new Runnable() {
             public void run() {
                 System.out.println("running!");
                 ReceiveMsg();
             }
         };   
         
         public void connect() {
             try {
                 s = new Socket();
                 isa = new InetSocketAddress(ip,Integer.parseInt(port)); 
                 s.connect(isa,5000); 
     
                 if(s.isConnected()){
                     dos = new DataOutputStream (s.getOutputStream());
                     dis = new DataInputStream (s.getInputStream());
                     dos.writeUTF(chatKey+"online:"+name);
                     /**
                      * 这里是关键,我在此耗时8h+
                      * 原因是 子线程不能直接更新UI
                      * 为此,我们需要通过Handler物件,通知主线程Ui Thread来更新界面。
                      * 
     */
                     thread = new Thread(null, doThread, "Message");
                       thread.start();
                       System.out.println("connect");
                       isContect=true;
                 }
               }catch (UnknownHostException e) {
                   System.out.println("連接失敗");
                 Toast.makeText(SocketmsgActivity.this, "連接失敗", Toast.LENGTH_SHORT).show();
                 Intent intent = new Intent(SocketmsgActivity.this,IniActivity.class);
                 startActivity(intent);
                 SocketmsgActivity.this.finish();
                   e.printStackTrace();
               }catch (SocketTimeoutException  e) {
                   System.out.println("連接超時,服務器未開啟或IP錯誤");
                   Toast.makeText(SocketmsgActivity.this, "連接超時,服務器未開啟或IP錯誤", Toast.LENGTH_SHORT).show();
                 Intent intent = new Intent(SocketmsgActivity.this,IniActivity.class);
                 startActivity(intent);
                 SocketmsgActivity.this.finish();
                   e.printStackTrace();
               }catch (IOException e) {
                   System.out.println("連接失敗");
                   e.printStackTrace();
               }
         }
        
         public void disConnect() {
             if(dos!=null){
             try {
                 
                     dos.writeUTF(chatKey+"offline:"+name);
                 
             } catch (IOException e1) {
                 // TODO Auto-generated catch block
                 e1.printStackTrace();
             }
             try {
                 s.close();
             } catch (IOException e) {
                   e.printStackTrace();
             }
             }
         }
       
         
         /**
          * 线程监视Server信息
     */
         private void ReceiveMsg() {
             if (isContect) {
                 try {
                     while ((reMsg = dis.readUTF()) != null) {
                         System.out.println(reMsg);
                         if (reMsg != null) {
     
                             try {
                                 Message msgMessage = new Message();
                                 msgMessage.what = 0x1981;
                                 handler.sendMessage(msgMessage);
                                 Thread.sleep(100);
                             } catch (InterruptedException e) {
                                 // TODO Auto-generated catch block
                                 e.printStackTrace();
                             }
     
                         }
                     }
                 } catch (SocketException e) {
                     // TODO: handle exception
                     System.out.println("exit!");
                 } catch (IOException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                 }
     
             }
         }
       
         /**
          * 通过handler更新UI
     */
         Handler handler = new Handler() {
             public void handleMessage(Message msg) {
                 switch (msg.what) {
                 case 0x1981:
                     chatbox.setText(chatbox.getText() + reMsg + '\n');
                     chatbox.setSelection(chatbox.length());
                     break;
                 }
             }
         };
         
         @Override
         protected void onDestroy() {
             // TODO Auto-generated method stub
             super.onDestroy();
             disConnect();
             //System.exit(0);
         }
         
         @Override
         public boolean onCreateOptionsMenu(Menu menu) {
             // TODO Auto-generated method stub
             menu.add(0, 1, 1, "初始化設置");
             menu.add(0, 2, 2, "退出");
             return super.onCreateOptionsMenu(menu);
         }
     
         @Override
         public boolean onOptionsItemSelected(MenuItem item) {
             // TODO Auto-generated method stub
             if(item.getItemId()==1){
                 Intent intent = new Intent(SocketmsgActivity.this,IniActivity.class);
                 startActivity(intent);
                 SocketmsgActivity.this.finish();
             }else if(item.getItemId()==2){
                 disConnect();
                 SocketmsgActivity.this.finish();  
                 android.os.Process.killProcess(android.os.Process.myPid());
                 System.exit(0);
             }
             return super.onOptionsItemSelected(item);
         }
     
         public void InitDatabase(){
              
             if(!config.path.exists()){  
                 config.path.mkdirs();    
                 Log.i("LogDemo", "mkdir");  
             }   
             if(!config.f.exists()){      
                 try{   
                     config.f.createNewFile();  
                     Log.i("LogDemo", "create a new database file");
                 }catch(IOException e){   
                     Log.i("LogDemo",e.toString());
                 }   
             }  
             try {
                 if(tabIsExist("config")==false){
                     db = SQLiteDatabase.openOrCreateDatabase(config.f, null);  
                     db.execSQL("create table config(_id integer primary key autoincrement," +
                             "ip varchar(128),port varchar(10),name varchar(32))");
                     Log.i("LogDemo", "create a database");
                     db.close();
                 }
             } catch (Exception e) {
                 // TODO: handle exception
                 Log.i("LogDemo",e.toString());
             }
         }
         
         /**
          * check the database is already exist
          * @param tabName
          * @return
     */
         public boolean tabIsExist(String tabName){
             boolean result = false;
             if(tabName == null){
                     return false;
             }
             Cursor cursor = null;
             db = SQLiteDatabase.openOrCreateDatabase(config.f, null); 
             try {
                 String sql = "select count(*) as c from sqlite_master where type ='table' " +
                             "and name ='"+tabName.trim()+"' ";
                 cursor = db.rawQuery(sql, null);
                 if(cursor.moveToNext()){
                     int count = cursor.getInt(0);
                     if(count>0){
                         result = true;
                     }
                 }
                     
             } catch (Exception e) {
                     // TODO: handle exception
             }  
             cursor.close();
             db.close();
             return result;
         }
     }

    2.初始化IP和端口Activity, IniActivity.java

    IniActivity.java 
     public class IniActivity extends Activity{
     
         private EditText ip,port;
         private Button nextButton;
         private String getip,getport;
         private ProgressDialog progressDialog;
         private InetSocketAddress isa = null; 
         private SQLiteDatabase db;
         private String ipstring=null,portString=null;
         private int row=0;
         @Override
         protected void onCreate(Bundle savedInstanceState) {
             // TODO Auto-generated method stub
             super.onCreate(savedInstanceState);
             setContentView(R.layout.config);
             
             ip = (EditText)findViewById(R.id.ip);
             port = (EditText)findViewById(R.id.port);
             nextButton = (Button)findViewById(R.id.next);
             
             
             db = SQLiteDatabase.openOrCreateDatabase(config.f, null);
             try {
                 Cursor cursor = db.query("config", new String[]{"ip","port"},null,null, null, null, null);
                 while(cursor.moveToNext()){
                     ipstring = cursor.getString(cursor.getColumnIndex("ip"));
                     portString = cursor.getString(cursor.getColumnIndex("port"));
                     row++;
                 }
                 ip.setText(ipstring);
                 port.setText(portString);
                 cursor.close();
             } catch (Exception e) {
                 // TODO: handle exception
                 System.out.println(e.toString());
             }
             db.close();
             
             nextButton.setOnClickListener(new nextButtonListenner());
         }
         
         class nextButtonListenner implements OnClickListener{
     
             @Override
             public void onClick(View v) {
                 // TODO Auto-generated method stub
                 getip = ip.getText().toString().trim();
                 getport = port.getText().toString().trim();
                 if(getip=="" || getip==null || getip.equals("")){
                     Toast.makeText(IniActivity.this, "請輸入IP", Toast.LENGTH_SHORT).show();
                     ip.setFocusable(true);
                 }else if(getport=="" || getport==null || getport.equals("")){
                     Toast.makeText(IniActivity.this, "請輸入端口", Toast.LENGTH_SHORT).show();
                     port.setFocusable(true);
                 }else{
                 //progressDialog = ProgressDialog.show(IniActivity.this, "", "請稍後...", true, false);
     //new Thread() {
     //@Override
     //public void run() {
                         try {
                             Socket s = new Socket();
                             isa = new InetSocketAddress(getip,Integer.parseInt(getport)); 
                             s.connect(isa,5000); 
                             //showDialog("連接成功",IniActivity.this);
                             try {
                                 //生成ContentValues对象
                                 ContentValues values = new ContentValues();
                                 //想该对象当中插入键值对,其中键是列名,值是希望插入到这一列的值,值必须和数据库当中的数据类型一致
                                 values.put("ip", getip);
                                 values.put("port",getport);
                                 db = SQLiteDatabase.openOrCreateDatabase(config.f, null); 
                                 if(row==0){
                                     db.insert("config", null, values);
                                 }else{
                                     db.update("config", values ,null,null);
                                 }
                                 Toast.makeText(IniActivity.this, "連接成功", Toast.LENGTH_SHORT);
                                 s.close();
                                 Intent intent = new Intent(IniActivity.this,IniuserActivity.class);
                                 startActivity(intent);
                                 IniActivity.this.finish();
                                 db.close();
                             } catch (Exception e) {
                                 // TODO: handle exception
                                 showDialog("設置失敗,數據庫不可用",IniActivity.this);
                             }
                             
                             
                         } catch (UnknownHostException e) {
                             // TODO Auto-generated catch block
                             e.printStackTrace();
                             showDialog("連接失敗,IP或者端口不可用",IniActivity.this);
                         }catch (SocketTimeoutException  e) {
                               System.out.println("連接超時,服務器未開啟或IP錯誤");
                               showDialog("連接超時,服務器未開啟或IP錯誤",IniActivity.this);
                               e.printStackTrace();
                         }
                         catch (IOException e) {
                             // TODO Auto-generated catch block
                             e.printStackTrace();
                             showDialog("連接失敗,IP或者端口不可用",IniActivity.this);
                         }
                         //progressDialog.dismiss();
     //finish();
     //}
     //}.start();
                 }
                 
             }
             
         }
         
         /**
          * define a dialog for show the message
          * @param mess
          * @param activity
     */
         public void showDialog(String mess,Activity activity){
           new AlertDialog.Builder(activity).setTitle("信息")
            .setMessage(mess)
            .setNegativeButton("確定",new DialogInterface.OnClickListener()
            {
              public void onClick(DialogInterface dialog, int which)
              {          
              }
            })
            .show();
         }
     }

    3.初始化用户名称Activity, IniuserActivity.java

    IniuserActivity.java 
     public class IniuserActivity extends Activity{
         private EditText name;
         private Button ok;
         private SQLiteDatabase db;
         
         private String nameString;
         @Override
         protected void onCreate(Bundle savedInstanceState) {
             // TODO Auto-generated method stub
             super.onCreate(savedInstanceState);
             setContentView(R.layout.configuser);
             
             name = (EditText)findViewById(R.id.name);
             ok = (Button)findViewById(R.id.ok);
             ok.setOnClickListener(new okButtonListenner());
             
             
             db = SQLiteDatabase.openOrCreateDatabase(config.f, null);
             try {
                 Cursor cursor = db.query("config", new String[]{"name"},null,null, null, null, null);
                 while(cursor.moveToNext()){
                     nameString = cursor.getString(cursor.getColumnIndex("name"));
                 }
                 name.setText(nameString);
                 cursor.close();
             } catch (Exception e) {
                 // TODO: handle exception
                 System.out.println(e.toString());
             }
             db.close();
         }
         
         class okButtonListenner implements OnClickListener{
     
             @Override
             public void onClick(View v) {
                 // TODO Auto-generated method stub
                 String getname = name.getText().toString().trim();
                 if(getname==""){
                     Toast.makeText(IniuserActivity.this, "請輸入您的稱呢", Toast.LENGTH_SHORT).show();
                     name.setFocusable(true);
                 }else{            
                     try {
                         //生成ContentValues对象
                         ContentValues values = new ContentValues();
                         //想该对象当中插入键值对,其中键是列名,值是希望插入到这一列的值,值必须和数据库当中的数据类型一致
                         values.put("name", getname);
                         db = SQLiteDatabase.openOrCreateDatabase(config.f, null); 
                         db.update("config",values,null,null);
                         Toast.makeText(IniuserActivity.this, "設置完成", Toast.LENGTH_SHORT).show();
                         Intent intent = new Intent(IniuserActivity.this,SocketmsgActivity.class);
                         startActivity(intent);
                         IniuserActivity.this.finish();
                         db.close();
                     } catch (Exception e) {
                         // TODO: handle exception
                         showDialog("設置失敗,數據庫不可用",IniuserActivity.this);
                     }
                 }
             }
             
         }
         
         /**
          * define a dialog for show the message
          * @param mess
          * @param activity
     */
         public void showDialog(String mess,Activity activity){
           new AlertDialog.Builder(activity).setTitle("信息")
            .setMessage(mess)
            .setNegativeButton("確定",new DialogInterface.OnClickListener()
            {
              public void onClick(DialogInterface dialog, int which)
              {          
              }
            })
            .show();
         }
     }

    4.config.java

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

    布局文件:

    1.main.xml

    main.xml 
     <?xml version="1.0" encoding="utf-8"?>
     <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
         android:orientation="vertical" android:layout_width="fill_parent"
         android:layout_height="fill_parent">
         <EditText android:id="@+id/chatbox" android:layout_width="fill_parent"
             android:layout_height="fill_parent" android:layout_weight="1">
         </EditText>
         <EditText android:id="@+id/chattxt" android:layout_width="fill_parent"
             android:layout_height="wrap_content" android:gravity="top"
             android:hint="你想和对方说点什么?">
         </EditText>
         <Button android:id="@+id/chatOk" android:layout_width="fill_parent"
             android:layout_height="wrap_content" android:text="Send" 
             android:textSize="@dimen/btn1">
         </Button>
     
     </LinearLayout>

    2.config.xml

    config.xml 
     <?xml version="1.0" encoding="utf-8"?>
     <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
         <TextView 
     android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:text="初始化設置"
             android:textSize="@dimen/h2"/>
         <TextView 
     android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:text="服務器IP"
             android:textSize="@dimen/h3"/>
         <EditText 
     android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:hint="192.168.2.214"
             android:id="@+id/ip"
             android:textSize="@dimen/et1"/>
             
         <TextView 
     android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:text="端口"
             android:textSize="@dimen/h3"/>
         <EditText 
     android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:hint="8888"
             android:id="@+id/port"
             android:textSize="@dimen/et1"/>
             
         <Button 
     android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:text="下一步"
             android:id="@+id/next"
             android:textSize="@dimen/btn1"/>        
     </LinearLayout>

    3.configuer.xml

    configuser.xml 
     <?xml version="1.0" encoding="utf-8"?>
     <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
         <TextView 
     android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:text="初始化設置"
             android:textSize="@dimen/h2"/>
         <TextView 
     android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:text="您的稱呢"
             android:textSize="@dimen/h3"/>
         <EditText 
     android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:hint="潤仔"
             android:id="@+id/name"
             android:maxLength="20"
             android:textSize="@dimen/et1"/>
             
         <Button 
     android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:text="完成"
             android:id="@+id/ok"
             android:textSize="@dimen/btn1"/>    
     </LinearLayout>

    style文件:dimens.xml

    dimens.xml 
     <?xml version="1.0" encoding="utf-8"?>
     <resources>     
         <dimen name="h3">30dip</dimen> 
         <dimen name="h2">40dip</dimen> 
         <dimen name="btn1">30dip</dimen>
         <dimen name="et1">25dip</dimen>
     </resources>

    最后是服务器文件:Server.java

    import java.io.*;
     import java.net.*;
     import java.text.DateFormat;
     import java.text.SimpleDateFormat;
     import java.util.*;
     
     import javax.sound.sampled.Port;
     import javax.swing.JOptionPane;
     
     public class Server {
         
         ServerSocket ss = null;
         private String getnameString=null;
         boolean started = false;
         List<Client> clients = new ArrayList<Client>();
         List<Info> infos = new ArrayList<Info>();
         public static void main(String[] args) {
             String inputport = JOptionPane.showInputDialog("請輸入該服務器使用的端口:");
             int port = Integer.parseInt(inputport);
             new Server().start(port);
         }
      
         public void start(int port) {
             try {
                ss = new ServerSocket(port);
                System.out.println("服務器啟動");
                started = true;
             } catch (BindException e) {
                   System.out.println(" 端口已经被占用");
                   System.exit(0);
                }
               catch (IOException e) {
                  e.printStackTrace();
               }
     
           try {
              while (started) {
                  Socket s = ss.accept();
                  Client c = new Client (s);
                  System.out.println("a client is connected");
                  new Thread(c).start();
                  clients.add(c);
                  
                  
              }
           } catch (IOException e) {
                 e.printStackTrace();
              }
              finally {
                 try {
                    ss.close();
                 } catch (IOException e) {
                       e.printStackTrace();
                    }
              }
        }
        public List<Client> getClient(){
            return clients;
        }
     
       class Client implements Runnable {
          private String chatKey="SLEEKNETGEOCK4stsjeS";
          private Socket s = null;
          private DataInputStream dis = null;
          private DataOutputStream dos = null;
          private boolean bConnected = false;
          private String sendmsg=null;
          Client (Socket s) {
             this.s = s;
             try {
               dis = new DataInputStream (s.getInputStream());
               dos = new DataOutputStream (s.getOutputStream());
               bConnected = true;
             } catch(IOException e) {
                   e.printStackTrace();
                }
          }
          
          public void send (String str) {
              
              try {
                  //System.out.println(s);
                  dos.writeUTF(str+"");
                  dos.flush();
              } catch(IOException e) {
                  clients.remove(this);
                  System.out.println("对方已经退出了");
              }
          }
          public void run() {
              try {
                 while (bConnected) {
                     String str = dis.readUTF();
                     DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                     String date = "  ["+df.format(new Date())+"]";
                     if(str.startsWith(chatKey+"online:")){
                         Info info = new Info();
                         getnameString = str.substring(27);
                         
                         info.setName(getnameString);
                         infos.add(info);
                         for (int i=0; i<clients.size(); i++) {
                           Client c = clients.get(i);
                           c.send(getnameString+" on line."+date);
                         }
                         System.out.println(getnameString+" on line."+date);
                     }else if(str.startsWith(chatKey+"offline:")){
                         getnameString = str.substring(28);
                         clients.remove(this);
                         for (int i=0; i<clients.size(); i++) {
                               Client c = clients.get(i);
                               c.send(getnameString+" off line."+date);
                             }
                         System.out.println(getnameString+" off line."+date);
                     }
                     else{
                         int charend = str.indexOf("end;");
                         String chatString = str.substring(charend+4);
                         String chatName = str.substring(25, charend);
                         
                         sendmsg=chatName+date+"\n"+chatString; 
                         for (int i=0; i<clients.size(); i++) {
                             Client c = clients.get(i);
                             c.send(sendmsg);
                           }
                         System.out.println(sendmsg);
                     }
                  }
              } catch (SocketException e) {
                  System.out.println("client is closed!");
                  clients.remove(this);
              } catch (EOFException e) {
                    System.out.println("client is closed!");
                    clients.remove(this);
                 }
                 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();
                    }
                }
          }
       }
       
       class Info{
           private String info_name = null;
           public Info(){
               
           }
           public void setName(String name){
               info_name = name;
           }
           public String getName(){
               return info_name;
           }
       }
     }

    以上只是一个粗略的聊天室功能,如果要实现私聊,还需要保存该Socket关联的客户信息。一个客户端可以将信息发送另一个指定客户端。实际上,我们知道所有客户端只与服务器连接,客户端之间并没有互相连接。

  • 相关阅读:
    VScode 修改中文字体
    missing KW_END at ')' near '<EOF>'
    SQL inner join, join, left join, right join, full outer join
    SQL字符替换函数translater, replace
    SQL COOKBOOK SQL经典实例代码 笔记第一章代码
    sqlcook sql经典实例 emp dept 创建语句
    dateutil 2.5.0 is the minimum required version python
    安装postgresql后找不到服务 postgresql service
    Postgres psql: 致命错误: 角色 "postgres" 不存在
    【西北师大-2108Java】第十六次作业成绩汇总
  • 原文地址:https://www.cnblogs.com/xuewater/p/2616061.html
Copyright © 2011-2022 走看看