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);

}

}

}

}

}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2025-01-03 17:44:01

Android开发之聊天室的相关文章

Android 基于XMPP Smack openfire 开发的聊天室

Android基于XMPP Smack openfire 开发的聊天室

Java和WebSocket开发网页聊天室

小编心语:咳咳咳,今天又是聊天室,到现在为止小编已经分享了不下两个了,这一次跟之前的又不大相同,这一次是网页聊天室,具体怎么着,还请各位看官往下看~ Java和WebSocket开发网页聊天室 一.项目简介 WebSocket是HTML5一种新的协议,它实现了浏览器与服务器全双工通信,这里就将使用WebSocket来开发网页聊天室,前端框架会使用AmazeUI,后台使用Java,编辑器使用UMEditor. 二.涉及知识点 网页前端(HTML+CSS+JS)和Java 三.软件环境 Tomcat

多人语音直播系统开发中聊天室功能实现方案?

"直播+"不仅是视频.直播平台的尝试方向,也成为众多音乐平台的创新业务,而语音直播正是其中一种尝试.语音直播的用户更偏向年轻化,多为追求新鲜感的90后群体,他们有自己的行为处事方式,喜欢把孤独和无聊的时间用声音的方式宣泄.对于喜爱声音的这类群体来说,语音直播系统开发既保护了他们的隐私又让他们倍感亲切.那么从技术层面讲,多人语音直播系统开发中聊天室的功能实现需要特别注意哪些呢?一.语音直播系统开发的优势是什么?想必有人会问语音直播和传统的电台有什么不同呢?语音直播也有着自己的优势主要有以

C# 异步通信 网络聊天程序开发 局域网聊天室开发

Prepare 本文将使用一个NuGet公开的组件技术来实现一个局域网聊天程序,利用组件提供的高性能异步网络机制实现,免去了手动编写底层的困扰,易于二次开发,扩展自己的功能. 在Visual Studio 中的NuGet管理器中可以下载安装,也可以直接在NuGet控制台输入下面的指令安装: Install-Package HslCommunication NuGet安装教程  http://www.cnblogs.com/dathlin/p/7705014.html 技术支持QQ群:592132

用swoole和websocket开发简单聊天室

首先,我想说下写代码的一些习惯,第一,任何可配置的参数或变量都要写到一个config文件中.第二,代码中一定要有日志记录和完善的报错并记录报错.言归正传,swoole应该是每个phper必须要了解的,它号称重新定义了php.此聊天室利用了swoole高并发并且异步非阻塞的特点提高了程序的性能. 首先,定义一个 swoole_lock 和 swoole_websocket_server ,并且配置参数,具体参数详情可以去swoole官网查看. public function start(){ $t

Android开发-图灵聊天机器人接口引用

转载注明出处: http://www.cnblogs.com/frank-zouxu/p/4121601.html  在前几日,偶然看到新闻,图灵机器人向开发者提供了API,API地址为:http://www.tuling123.com/openapi/,因为这个API可以定制自己的聊天机器人,这在我看来,是个很有意思的事情,于是我就试着在Android应用中进行了API测试,效果图如下(图1): 图1 主要代码如下: public class MainActivity extends Acti

基于Android的串口聊天室 (基于tiny4412) 一

硬件平台: tiny4412ADK + S700 4GB Flash Android版本:Android-5.0.2 Linux版本: Linux-3.0.86 Bootloader:Superboot 下面的例子是基于Andrioid源码中自带的一个串口应用SerialChat,Android已经把与之相关的Freamwork.JNI代码,其中直接在JNI中调用了Linux的系统调用,没有遵循Android的HAL架构,根本就没有提供HAL. 下面是相关的代码路径: APP: framewor

zphp,swoole开发chat聊天室

centos6.8 我之前在系统上安装了php7还有swoole扩展 可以用命令查看扩展有没有装好 php -i|grep swoole  (没装的直接看我之前文章吧,或者留言我告诉你怎么装) git clone https://github.com/shenzhe/zphp.git(克隆框架下来) cd zphp php build.php(构建项目) pls enter app path: /home/skinglzw/Documents/chat_zphp(提示要你填项目路径) pls e

以C#编写的Socket服务器的Android手机聊天室Demo

 内容摘要  1.程序架构    2.通信协议    3.服务器源代码    4.客户端源代码    5.运行效果  一.程序架构 在开发一个聊天室程序时,我们可以使用Socket.Remoting.WCF这些具有双向通信的协议或框架.而现在,我正要实现一个C#语言作为服务器端.Android作为客户端的聊天室.由于服务器端和客户端不是同一语言(C#和java),所有我选择了Socket作为通信协议. 图1.1所示,我们可以看出:android手机客户端A向服务器端发送消息,服务器端收到消息后,