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关联的客户信息。一个客户端可以将信息发送另一个指定客户端。实际上,我们知道所有客户端只与服务器连接,客户端之间并没有互相连接。

  • 相关阅读:
    Cannot assign requested address问题总结
    Trying to connect an http1.x server
    从 0 到 1 搭建技术中台之推送平台实践:高吞吐、低延迟、多业务隔离的设计与实现
    思考gRPC :为什么是HTTP/2
    HTTP/1HTTP/2HTTP/3
    get_or_create update_or_create
    死锁案例 GAP 锁 没有就插入,存在就更新
    死锁产生必要条件
    京东零售mockRpc实践
    Certbot CA 证书 https
  • 原文地址:https://www.cnblogs.com/xuewater/p/2616061.html
Copyright © 2011-2022 走看看