欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 基于Socket的聊天室实例

程序员文章站 2024-02-28 17:02:10
socket是tcp/ip协议上的一种通信,在通信的两端各建立一个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运行起来,然后再运行手机模拟器

Android 基于Socket的聊天室实例

服务器打印信息:

Android 基于Socket的聊天室实例

程序文件结构:

Android 基于Socket的聊天室实例

1.先看看主activity : 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

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

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

<?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

<?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

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。