Android开发之聊天室
Posted 骨灵冷
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android开发之聊天室相关的知识,希望对你有一定的参考价值。
本案例目的在于开发一个简单的聊天室功能,所有代码都是本人调试修改之后可以正常使用,主要功能在于通过多线程技术由服务器接收客户端的请求,之后将聊天内容发送给每个接入服务器的每个客户端。另外实现了登录功能,只有登录验证之后才可以实现聊天。具体的技术细节在本栏目不涉及,主要是多线程基于Socket,具体代码如下:
首先是简易的聊天模型图:
客户端代码如下:
功能为指定socket连接的ip地址和端口号,客户端分为2个线程A和B,其中A线程负责登录连接,B线程分为2个子线程,第一个是向服务器发送数据,第2个为从服务器接收数据
public class MainActivity extends Activity
/**
* IP地址及端口号配置
*/
private final static String IP_ADDRESS = "172.21.212.158";
private final static int PORT = 12345;
/**
* 控件变量
*/
private Button btn_sent,btn_loadon;
private EditText editText,edit_username,edit_password;
private TextView tv_content;
private boolean isConn = false;
private Handler handler = new Handler()
public void handleMessage(Message msg)
if (msg.obj.toString().contains("登录成功"))
isConn = true;
showToast(msg.what,msg.obj);
;
;
private ClientThread clientThread;
private Socket socket ;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/**
* 初始化控件
*/
btn_sent = (Button) findViewById(R.id.btn_sent);
editText = (EditText) findViewById(R.id.edit_text);
tv_content = (TextView) findViewById(R.id.tv_content);
btn_loadon = (Button) findViewById(R.id.btn_loadon);
edit_password = (EditText) findViewById(R.id.edit_password_input);
edit_username = (EditText) findViewById(R.id.edit_username_input);
btn_loadon.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
//获取登录名和密码
String user = edit_username.getText().toString().trim();
String pass = edit_password.getText().toString().trim();
//启动登录线程
new Thread(new ConnServer(user, pass)).start();
);
if (socket == null)
Toast.makeText(getApplicationContext(), "Null Socket", Toast.LENGTH_SHORT).show();
//响应发送按钮
btn_sent.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
// TODO Auto-generated method stub
//将要发送的内容包装给成消息,因为后面要发送给服务器
new NewClientTask(socket).execute(editText.getText().toString().trim()+"\\n");
editText.setText("");
);
public void showToast(int flag,Object msgobj)
switch (flag)
case 0:
Toast.makeText(this, msgobj.toString(), Toast.LENGTH_SHORT).show();
break;
case 1:
Toast.makeText(this, msgobj.toString(), Toast.LENGTH_SHORT).show();
default:
break;
/**
* 连接服务器的线程
*/
private class ConnServer implements Runnable
private String username = null;
private String password = null;
private int waitTime = 0;
private boolean hasSendConnMessage = false;
public ConnServer(String user,String pass)
this.username = user;
this.password = pass;
//创建构造函数
@Override
public void run()
// TODO Auto-generated method stub
try
//向服务器传递数据
socket = new Socket(IP_ADDRESS, PORT);
OutputStream os = socket.getOutputStream();
byte[] buffer = new byte[512];
String str = this.username+"#"+this.password;
buffer = str.getBytes();
os.write(buffer);
hasSendConnMessage = true;
catch (UnknownHostException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
InputStream is = null;
if (hasSendConnMessage)
try
is = socket.getInputStream();
while (is == null)
waitTime += 1000;
byte[] buffer2 = new byte[512];
is.read(buffer2);
String reuslt = new String(buffer2,"utf-8");
//建立一个消息
Message msg = new Message();
msg.what = 1;
msg.obj = reuslt;
handler.sendMessage(msg);
buffer2 = null;
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
if (waitTime > 5000)
Message msg = new Message();
msg.what = 0;
msg.obj = "登录超时";
handler.sendMessage(msg);
/**
* 客户端线程类,实现了Runnble接口
* @author sjm
*
*/
private class NewClientTask extends AsyncTask<String, Void, String>
private Socket clientScoket ;
public NewClientTask(Socket s)
this.clientScoket = s;
@Override
protected void onPostExecute(String result)
// TODO Auto-generated method stub
tv_content.append(result+"\\n");
@Override
protected String doInBackground(String... params)
// TODO Auto-generated method stub
//接收自服务器的数据
String result = null;
StringBuilder sb = new StringBuilder();
try
//发送给服务器
OutputStream os = clientScoket.getOutputStream();
os.write(params[0].getBytes("utf-8"));
InputStream is = clientScoket.getInputStream();
byte[] buffer = new byte[512];
is.read(buffer);
result = new String(buffer, "utf-8");
catch (UnknownHostException e)
// TODO Auto-generated catch block
try
clientScoket.close();
catch (IOException e1)
// TODO Auto-generated catch block
e1.printStackTrace();
e.printStackTrace();
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
return result;
接下来是服务器的功能:主要是用于验证登录,以及分发收到的聊天消息,需要注意的是用户名与密码发送给服务器的格式需要自定义,这里我用的是USER#PASS:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.ObjectInputStream.GetField;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.logging.Handler;
/**
* 我的服务器:用来接收客户端的消息,并且把消息再发送给每个客户端
* @author sjm
*
*/
public class MyServer
//建立socketArray对象存储各个socket
public static ArrayList<Socket> socketArray = new ArrayList<Socket>();
private final static int PORT = 12345;
private static String USERNAME = "SJM";
private static String PASSWORDS = "1234";
private static Socket clientsocket = null;
private static boolean hasClient = false;
public static void main(String[] args)
// TODO Auto-generated method stub
//1、启动服务端
try
ServerSocket server = new ServerSocket(PORT);
while(true)
System.out.println("等待一个连接:");
clientsocket = server.accept();
System.out.println("接收到一个连接请求");
//将该客户端socket放置到socketArray当中
//设置登录权限,当用户名与密码均满足条件时才开辟线程
//实现方法是开辟一个验证登录的线程,满足则继续
new Thread(new clientPermission(clientsocket)).start();
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
/**
* 验证登录的线程
* @author sjm
*
*/
private static class clientPermission implements Runnable
private Socket socket;
private String userName = null;//用户名
private String passWords = null;//密码
public clientPermission(Socket s)
this.socket = s;
@Override
public void run()
// TODO Auto-generated method stub
try
InputStream is = this.socket.getInputStream();
byte[] buffer = new byte[512];
is.read(buffer);
String br = new String(buffer);
System.out.println(br);
//用户名和密码的数据格式是在传入过来的时候自定义的,如username#passwords
if (br != null)
String str = br.toString();
String[] str2 = str.split("#");
userName = str2[0];
passWords = str2[1];
System.out.println(str);
hasClient = userName.contains(USERNAME)&&passWords.contains(PASSWORDS)?true:false;
System.out.println(String.valueOf(hasClient));
if (hasClient)
//若验证正确
socketArray.add(socket);
//返回一个消息
OutputStream os = socket.getOutputStream();
os.write(new String("登录成功").getBytes("utf-8"));
buffer = null;
//为该客户端开辟一个线程
new Thread(new serverThread(socket)).start();
else
OutputStream os = socket.getOutputStream();
os.write(new String("密码错误").getBytes("utf-8"));
is.close();
socket.close();
socketArray.remove(socket);
return ;
else
OutputStream os = socket.getOutputStream();
os.write(new String("密码不能为空").getBytes("utf-8"));
is.close();
socket.close();
socketArray.remove(socket);
return;
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
private static class serverThread implements Runnable
private Socket client_Socket;
/**
* 线程构造函数
* @param s
*/
public serverThread(Socket s)
this.client_Socket = s;
@Override
public void run()
// TODO Auto-generated method stub
try
System.out.println("启动啦");
while(true)
String str = null;
byte[] buffer = new byte[512];
InputStream is = client_Socket.getInputStream();
if (is != null)
is.read(buffer);
//str = new String(buffer, "utf-8");
//System.out.println("接收到消息"+str);
for(Socket s : socketArray)
OutputStream os = s.getOutputStream();
os.write(buffer);
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
if (client_Socket != null)
socketArray.remove(client_Socket);
以上是关于Android开发之聊天室的主要内容,如果未能解决你的问题,请参考以下文章