栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 移动开发 > Android

Android 基于Socket的聊天室实例

Android 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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 clients = new ArrayList();

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

下面来看看整个功能的demo

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

服务器打印信息:

程序文件结构:

1.先看看主Activity : SocketmsgActivity.java

public class SocketmsgActivity extends Activity {
  
  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);
 
 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();
    }
    }
  }
 
  
  
  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 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());
    }
  }
  
  
  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();
      }
      
    }
    
  }
  
  
  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);
 }
      }
    }
    
  }
  
  
  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



  
  
  
  
  



2.config.xml



  
  
  
    
  
  
    
  

3.configuer.xml



  
  
  
    
  

最后是服务器文件: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 clients = new ArrayList();
  List infos = new ArrayList();
  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 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

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

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/160397.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号