展会信息港展会大全

Android 基于Socket的聊天室
来源:互联网   发布日期:2015-09-28 16:16:49   浏览:2942次  

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

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

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 (SocketTimeoutExceptione) {

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 (SocketTimeoutExceptione) {

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 (SocketTimeoutExceptione) {

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="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>

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="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>

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关联的客户信息。一个客户端可以将信息发送另一个指定客户端。

赞助本站

人工智能实验室

相关热词: Socket 聊天室

AiLab云推荐
推荐内容
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港