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运行起来,然后再运行手机模拟器

服务器打印信息:

程序文件结构:

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

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

(0)

相关推荐

  • Android使用多线程进行网络聊天室通信

    TCP/IP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket,从而在通信的两端之间形成网络虚拟链路.一旦建立了虚拟的网络链路,两端的程序就可以通过虚拟链路进行通信了.Java对基于TCP协议的网络通信提供了良好的封装,Java使用Socket对象来代表两端通信接口,并通过Socket产生IO流来进行网络通信. 下面的程序Demo是实现一个简单的C/S聊天室的应用,每个客户端该包含两条线程:一条负责生成主界面,响应用户动作,并将用户输入的数据写入Socket对应的输出流中:另一条

  • Android中基于XMPP协议实现IM聊天程序与多人聊天室

    简单的IM聊天程序 由于项目需要做一个基于XMPP协议的Android通讯软件.故开始研究XMPP. XMPP协议采用的是客户端-服务器架构,所有从一个客户端发到另一个客户端的消息和数据都必须经过XMPP服务器转发,而且支持服务器间DNS的路由,也就是说可以构建服务器集群,使不同的 服务器下的客户端也可以通信,XMPP的前身是一个开源组织制定的网络通信协议--Jabber,XMPP的核心是在网络上分片段发送XML流的协议,这个协议是XMPP的即时通讯指令的传递手段.       为了防止服务器间

  • android socket聊天室功能实现

    前提概要 笔者很久之前其实就已经学习过了socket,当然也是用socket做过了聊天室,但是觉得此知识点比较一般,并无特别难的技术点,于是也并未深究. 然而近期一个项目中对socket的使用却让笔者感觉socket强大无比,可以实现诸多功能. 个人Socket体验 项目主要有关智能家居,需要实现多台手机同时对灯进行操作(开或者关),主要需要实现以下几点: 1.进入界面时获取所有灯的状态. 2.一台手机改变了灯的状态,其他的手机上可以有所显示. 3.硬件上改变了灯的状态(手动开关灯),所有手机上

  • Android编写简单的聊天室应用

    最近写了一个简单的聊天室应用,可以发送表情,更改头像这些功能.主要技术点就是怎样把表情图片放到textview等Ui控件中展示.这里废话不多说,下面是效果图: 这里主要讲下怎样把文本替换到表情,先说下思路,首先我们的图片是保存在本地资源目录drawable中而所有的资源文件都是R这个类来管理,所以我们可以利用正则表达式找出图片id包装成ImageSpan然后把ImageSpan放到SpannableString中,最后把SpannableString放入edittext中,下面是源码: pack

  • Android 基于Socket的聊天室实例

    Socket是TCP/IP协议上的一种通信,在通信的两端各建立一个Socket,从而在通信的两端之间形成网络虚拟链路.一旦建立了虚拟的网络链路,两端的程序就可以通过虚拟链路进行通信. Client A  发信息给 Client B ,  A的信息首先发送信息到服务器Server ,Server接受到信息后再把A的信息广播发送给所有的Clients 首先我们要在服务器建立一个ServerSocket ,ServerSocket对象用于监听来自客户端的Socket连接,如果没有连接,它将一直处于等待

  • Android 基于Socket的聊天应用实例(二)

    前言 很久没写BLOG了,之前在写Android聊天室的时候答应过要写一个客户(好友)之间的聊天demo,Android 基于Socket的聊天室已经实现了通过Socket广播形式的通信功能. 以下是我写的一个类似现在多数聊天软件的冒泡聊天APP.全部功能都是自己的想法,对于现在市面上成功的例子是怎么实现的,我还不了解.所以读者可只做参考学习,也可以分享您的案例给我. 功能 一对一聊天,非聊天室 好友列表 好友在线,离线状态(实时更新) 冒泡实时聊天窗口 发送离线信息 基本原理 之前的聊天室原理

  • Android使用Websocket实现聊天室

    最近的项目中要实现一个聊天的功能,类似于斗鱼TV的聊天室功能,与服务器端人商量后决定用WebSocket来做,但是在这之前我只知道Socket但是听都没有听过WebSocket,但是查看了相关的材料以后发现实现一个聊天室其实是很简单的!下面我们先来看看WebSocket. Autobahn|Android 是由Autobahn开发一个开源的Java/Android网络库,实现了WebSocket协议和Web应用程序消息传输协议来创建本地移动的WebSocket/ WAMP的客服端. WebSoc

  • Android基于socket实现的简单C/S聊天通信功能

    本文实例讲述了Android基于socket实现的简单C/S聊天通信功能.分享给大家供大家参考,具体如下: 主要想法:在客户端上发送一条信息,在后台开辟一个线程充当服务端,收到消息就立即回馈给客户端. 第一步:创建一个继续Activity的SocketClientActity类,包为com.pku.net 编写布局文件socketclient.xml,代码如下: <?xml version="1.0" encoding="utf-8"?> <Lin

  • php+html5基于websocket实现聊天室的方法

    本文实例讲述了php+html5基于websocket实现聊天室的方法.分享给大家供大家参考.具体如下: html5的websocket 实现了双向通信,折腾了几天弄了个聊天室,分享给大家 <?php error_reporting(E_ALL); ob_implicit_flush(); $sk=new Sock('127.0.0.1',8000); $sk->run(); class Sock{ public $sockets; public $users; public $master;

  • C#基于WebSocket实现聊天室功能

    本文实例为大家分享了C#基于WebSocket实现聊天室功能的具体代码,供大家参考,具体内容如下 前面两篇温习了,C# Socket内容 本章根据Socket异步聊天室修改成WebSocket聊天室 WebSocket特别的地方是 握手和消息内容的编码.解码(添加了ServerHelper协助处理) ServerHelper: using System; using System.Collections; using System.Text; using System.Security.Cryp

  • 使用Java和WebSocket实现网页聊天室实例代码

    在没介绍正文之前,先给大家介绍下websocket的背景和原理: 背景 在浏览器中通过http仅能实现单向的通信,comet可以一定程度上模拟双向通信,但效率较低,并需要服务器有较好的支持; flash中的socket和xmlsocket可以实现真正的双向通信,通过 flex ajax bridge,可以在javascript中使用这两项功能. 可以预见,如果websocket一旦在浏览器中得到实现,将会替代上面两项技术,得到广泛的使用.面对这种状况,HTML5定义了WebSocket协议,能更

  • react native 仿微信聊天室实例代码

    一.前言 9月,又到开学的季节.为每个一直默默努力的自己点赞!最近都沉浸在react native原生app开发中,之前也有使用vue/react/angular等技术开发过聊天室项目,另外还使用RN技术做了个自定义模态弹窗rnPop组件. 一.项目简述 基于react+react-native+react-navigation+react-redux+react-native-swiper+rnPop等技术开发的仿微信原生App界面聊天室--RN_ChatRoom,实现了原生app启动页.As

  • unity使用socket实现聊天室功能

    本文实例为大家分享了unity使用socket实现聊天室的具体代码,供大家参考,具体内容如下 unity聊天室服务端实现 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Net.Sockets; using System.Net; namespace 服务端_03 { class Prog

  • Java创建多线程局域网聊天室实例

    局域网聊天室 在学习了一个学期的java以后,觉得java真是博大精深,彻底放弃了因为c++而轻视java的心态,搞了一个多线程的聊天室,熟悉了一下服务器和客户机的操作. 1.TCP 要实现局域网连接,就必须知道信息传输的原理. 在局域网里面传输的信息都是以包的形式,我使用的TCP包传输数据,TCP包里面封装了IP报文. 下面这句话就是通过一个静态IPV4协议的类得到一个服务器的IP地址. address = InetAddress.getByName("192.168.43.86")

随机推荐