基于Socket的Android聊天室

Posted 叶子8324

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于Socket的Android聊天室相关的知识,希望对你有一定的参考价值。

1        基于Socket的android聊天室

Socket通信是网络通信中最常用的技术之一,通过Socket建立的可靠连接,可以让多个终端与服务器保持通信,最典型的应用是建立一个多人聊天程序。本实例使用ServerSocket建立聊天服务器。将服务器端所有的通讯线程保存到一个集合当中,当有用户发来数据,则转发给所有用户,实现聊天室效果。Android端通过使用Socket建立客户端链接,并且在AsyncTask中执行网络读写的任务,将用户输入的内容发送到服务器,并接收服务器发来的数据,显示到界面上。开启多个虚拟机模拟多人聊天效果。

1.1     Socket聊天基本步骤

1,建立socket服务

2,等待连接

3,将建立的连接放在新的线程里

4,由于每个socket客户端连接相互独立,所以他们之间无法通信

5,使用一个类对新建的客户端线程进行管理,然后实现相互通信,管理类要做成单例,保证唯一性,并通过服务类进行转发来实现客户端相互通信

1.2     项目使用说明

1,下载源码 基于Socket的Android聊天室

2,将db_chat.sql导入到mysql数据库

3,将SocketChatServer项目导入到Eclipse,配置Tomcat下运行。

修改hibernate配置文件,改成修改成自己的环境


4,将SocketChat项目导入到Eclipse,配置Android环境并编译运行。

1.3     java web服务端

1.3.1   开启socket服务线程

使用Servlet init方法中调用启动线程,并在web.xml配置自启动。就可以在服务启动的时候启动socket服务。

package com.jie.socket.chat;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

/**
 * @ClassName: MyServerSocket.java
 * @Description: TODO(Socket服务端)
 * @author yangjie
 * @version V1.0
 * @Date 2016年5月23日 下午3:03:16
 */
public class MyServerSocket extends HttpServlet 
	private static final long serialVersionUID = 1L;

	@Override
	public void init() throws ServletException 
		// TODO Auto-generated method stub
		new ServerListenerThread().start();// 开启线程
		System.out.println("开启socket服务…………………………");
		// 在windows cmd下输入
		// telnet localhost 12345
		// 即可建立socket连接
	




1.3.2   socket服务监听线程(ServerListenerThread.java)

用于开启socket服务,并进行监听客户端连接

客户端首次接入,传递自己的名称,格式“name:***”

将连接的客户端,传入到客户端管理类中。

package com.jie.socket.chat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.JOptionPane;

/**
 * @ClassName: ServerListenerThread.java
 * @Description: TODO(ServerSoket监听线程)
 * @author yangjie
 * @version V1.0
 * @Date 2016年5月23日 下午3:38:17
 */
public class ServerListenerThread extends Thread 
	int i=1001;
	@Override
	public void run() 
		// TODO Auto-generated method stub
		super.run();
		try 
			ServerSocket serverSocket = new ServerSocket(12345);
			// 循环监听连接
			while (true) 
				// 阻塞block
				Socket socket = serverSocket.accept();
				// 建立连接
				// 在浏览器中输入:http://localhost:12345/
				// 会弹出提示框,点击确定后断开连接
				//JOptionPane.showMessageDialog(null, "有客户端连接到本机");
				// 将Socket传递给新的线程,每个socket享受独立的连接
				// new ChatSocket(socket).start();//开启chatSocket线程
				BufferedReader br = new BufferedReader(new InputStreamReader(
						socket.getInputStream(), "utf-8"));
				String line = null;
				String name = null;
				if ((line = br.readLine())!=null) //接收到客户端数据
					if(line.indexOf("name:")!=-1)
						name = line.substring(line.indexOf("name:")+5);
						System.out.println(name+":连接到本机");
					
				
				//br.close();//关闭输入流
				ChatSocket chatSocket = new ChatSocket(socket, name);
				chatSocket.start();
				ChatManager.getChatManager().add(chatSocket);
				i++;
			
		 catch (IOException e) 
			// TODO Auto-generated catch block
			e.printStackTrace();
		
	


1.3.3   socke客户端线程(ChartSocket.java)

Socket客户端线程,通过该线程类发送和接收信息。

package com.jie.socket.chat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.Socket;

/**
 * @ClassName: ChatSocket.java
 * @Description: TODO(socket客户端线程)
 * @author yangjie
 * @version V1.0
 * @Date 2016年5月23日 下午3:41:13
 */
public class ChatSocket extends Thread 
	Socket socket;
	String sName;

	/**
	 * 构造函数
	 */
	public ChatSocket(Socket socket, String sName) 
		// TODO Auto-generated constructor stub
		this.socket = socket;
		this.sName = sName;
	

	@Override
	public void run() 
		// TODO Auto-generated method stub
		// 输入
		try 
			BufferedReader br = new BufferedReader(new InputStreamReader(
					socket.getInputStream(), "utf-8"));
			String line = null;
			while ((line = br.readLine()) != null) // 接收到客户端数据
				System.out.println(getsName() + ":" + line);
				ChatManager.getChatManager().publish(this, line);
			
			br.close();// 关闭输入流
		 catch (UnsupportedEncodingException e) 
			// TODO Auto-generated catch block
			e.printStackTrace();
		 catch (IOException e) 
			// TODO Auto-generated catch block
			e.printStackTrace();
		
	

	public void out(String out) 
		// TODO Auto-generated method stub
		try 
			socket.getOutputStream().write(out.getBytes("UTF-8"));
		 catch (UnsupportedEncodingException e) 
			// TODO Auto-generated catch block
			e.printStackTrace();
		 catch (IOException e) 
			// TODO Auto-generated catch block
			if ("Socket is closed".equals(e.getMessage())) // 对于已经关闭的连接从管理器中删除
				System.out.println(e.getMessage());
				ChatManager.getChatManager().remove(this);
			
			// e.printStackTrace();
		
	

	public String getsName() 
		return sName;
	

	public void setsName(String sName) 
		this.sName = sName;
	



1.3.4   客户端管理类(ChatManager.java)

用于管理客户端,保存所有客户端信息,传输客户端发送的信息。

package com.jie.socket.chat;

import java.util.Vector;

/**
 * @ClassName:     ChatManager.java
 * @Description:   TODO(socket客户端连接管理类,单例) 
 * @author         yangjie
 * @version        V1.0  
 * @Date           2016年5月23日 下午4:25:38 
 */
public class ChatManager 
	private static final ChatManager chatManager = new ChatManager();
	private ChatManager()		
	
	public static ChatManager getChatManager()
		return chatManager;
	
	Vector<ChatSocket> vector = new Vector<ChatSocket>();
	/**
	 * @Title: add
	 * @Description: TODO(向集合中增加ChatSocket)
	 * @param chatSocket   
	 * @return: void   
	 * @throws
	 */
	public void add(ChatSocket chatSocket)
		vector.add(chatSocket);
	
	public void remove(ChatSocket chatSocket)
		vector.remove(chatSocket);
	
	/**
	 * @Title: publish
	 * @Description: TODO(向其他ChatSocket连接发送信息)
	 * @param chatSocket
	 * @param out   
	 * @return: void   
	 * @throws
	 */
	public void publish(ChatSocket chatSocket,String out)
		for(int i =0;i<vector.size();i++)
			ChatSocket cs = vector.get(i);
			if(!cs.equals(chatSocket))//发给不是自己的其他人
				cs.out(out+"\\n");
			
		
	


 

1.3.5   Hibernate工具类

hibernate工具类,用于连接数据库,操作数据库

package com.jie.socket.chart.util;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;

/**
 * @ClassName: HibernateUtil.java
 * @Description: TODO(Hibernate数据库工具类)
 * @author yangjie
 * @version V1.0
 * @Date 2016-5-16 上午11:42:11
 */
@SuppressWarnings("deprecation")
public class HibernateUtil 
	private static SessionFactory sessionFacotry = buildSessionFactory();

	private static SessionFactory buildSessionFactory() 
		// TODO Auto-generated method stub
		try 
			Configuration cfg = new Configuration();
			cfg.configure();
			ServiceRegistry sr = new ServiceRegistryBuilder().applySettings(
					cfg.getProperties()).buildServiceRegistry();
			return cfg.buildSessionFactory(sr);
		 catch (Exception e) 

		
		return null;
	

	public static SessionFactory getSessionFacotry() 
		return sessionFacotry;
	


 

1.3.6   用户实体

用于保存用户信息,关联数据库中的用户表

package com.jie.socket.chart.vo;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;

/**
 * @ClassName: User.java
 * @Description: TODO(用户实体类)
 * @author yangjie
 * @version V1.0
 * @Date 2016-5-24 下午9:17:10
 */
@Entity
@Table(name = "User")
public class User 
	@Id
	@GeneratedValue(generator = "userIdGenerator")
	@GenericGenerator(name = "userIdGenerator", strategy = "uuid")
	private String id;
	@Column
	private String name;
	@Column
	private String password;

	public String getId() 
		return id;
	

	public void setId(String id) 
		this.id = id;
	

	public String getName() 
		return name;
	

	public void setName(String name) 
		this.name = name;
	

	public String getPassword() 
		return password;
	

	public void setPassword(String password) 
		this.password = password;
	



1.3.7   用户登录Servlet

处理用户登陆验证,通过数据库验证。

package com.jie.socket.chat;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;

import com.jie.socket.chat.util.HibernateUtil;
import com.jie.socket.chat.vo.User;

/**
 * @ClassName:     ChatLogin.java
 * @Description:   TODO(登陆) 
 * @author         yangjie
 * @version        V1.0  
 * @Date           2016-5-16 上午11:20:16
 */

public class ChatLogin extends HttpServlet 
	private static final long serialVersionUID = 1L;

	public ChatLogin() 
		super();
	

	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException 
		doPost(request, response);
	

	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException 
		//int uuid = Integer.parseInt(request.getParameter("uuid"));
		String name = request.getParameter("name");
		String password = request.getParameter("password");
		//System.out.println(uuid);
		System.out.println(name);
		System.out.println(password);
		//是否登陆
		boolean islogin = false;
		if (!islogin) 
			// 查询用户表,验证登录 
			SessionFactory sf = HibernateUtil.getSessionFacotry();
			Session session = sf.openSession();
			Criteria criteria = session.createCriteria(User.class);
			//criteria.add(Restrictions.eq("uuid", uuid));
			criteria.add(Restrictions.eq("name", name));//按照姓名查找
			criteria.add(Restrictions.eq("password", password));//按照密码查找
			List<User> result = criteria.list();
			if (result.size() ==1) //登陆成功
				System.out.println(name+",登陆成功");
				islogin = true;
			else//登录失败
				System.out.println(password+",登陆失败");
			
			session.close();
			sf = null;
		
		PrintWriter out = response.getWriter();
		out.print(islogin);//传递登陆是否成功
		out.flush();
		out.close();
	



 

1.3.8   hibernate.cfg.xml配置文件

配置数据库信息,实体类信息。

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

	<session-factory>

		<!-- Database connection settings -->
		<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="connection.url">jdbc:mysql://192.168.0.99:3306/jie-db</property>
		<property name="connection.username">root</property>
		<property name="connection.password">bonc123,</property>

		<!-- JDBC connection pool (use the built-in) -->
		<property name="connection.pool_size">1</property>

		<!-- 方言,针对不同的数据库不一样 -->
		<property name="dialect">org.hibernate.dialect.MySQLDialect</property>

		<!-- Enable Hibernate's automatic session context management -->
		<property name="current_session_context_class">thread</property>

		<!-- Disable the second-level cache -->
		<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>

		<!-- 打印sql语句 -->
		<property name="show_sql">true</property>

		<!-- 时候让hibernate自动生成建表语句 -->
		<property name="hbm2ddl.auto">update</property>
		<!-- xml实体类映射文件 -->
		<!-- <mapping resource="com/jie/hibernate/po/Student.hbm.xml"/> -->

		<!-- Annotation实体类映射文件 -->
		<mapping class="com.jie.socket.chat.vo.User" />

	</session-factory>

</hibernate-configuration>


1.3.9   web.xml

配置servlet登陆类,自启动socket服务。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <display-name></display-name>
  <servlet>
    <description>自启动servlet,用于开启socket服务</description>
    <servlet-name>myServerSocket</servlet-name>
    <servlet-class>com.jie.socket.chat.MyServerSocket</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet>
    <description>手机登陆</description>
    <servlet-name>chatLogin</servlet-name>
    <servlet-class>com.jie.socket.chat.ChatLogin</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>chatLogin</servlet-name>
    <url-pattern>/chatLogin</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>


1.4     Android手机端

基于socket技术,通过网络端开启SocketServer服务,手机端登陆并连接SocketServer服务,通过socket客户端将消息发送到服务端,服务端分发给连接到该服务的所有客户端。实现手机群聊的效果。

1.4.1   用户信息类

通过SharedPreferences将用户名称存储到手机中。

package com.jie.socket.chat.info;

import java.io.Serializable;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;

public class UserInfo implements Serializable 

	private static final long serialVersionUID = 1L;
	private static final String PREFERENCES_TAG = "com.jie.socket.chart";
	private static UserInfo instance;
	private String name = "";

	public static UserInfo getInstance() 
		if (instance == null) 
			synchronized (UserInfo.class) 
				if (instance == null) 
					instance = new UserInfo();
				
			
		
		return instance;
	

	public static void saveName(Context context) 
		SharedPreferences mySharedPreferences = context.getSharedPreferences(
				PREFERENCES_TAG, Activity.MODE_PRIVATE);
		SharedPreferences.Editor edit = mySharedPreferences.edit();
		edit.putString("name", getInstance().getName());
		edit.commit();
	

	public static String readName(Context context) 
		SharedPreferences mySharedPreferences = context.getSharedPreferences(
				PREFERENCES_TAG, Activity.MODE_PRIVATE);
		String mName = mySharedPreferences.getString("name", "");
		getInstance().setName(mName);
		return mName;
	

	public static void readAll(Context context) 
		readName(context);
	

	public void cleanUserInfo(Context context) 
		SharedPreferences mySharedPreferences = context.getSharedPreferences(
				PREFERENCES_TAG, Activity.MODE_PRIVATE);
		SharedPreferences.Editor editor = mySharedPreferences.edit();
		editor.remove("name");
		editor.commit();
	

	public String getName() 
		return name;
	

	public void setName(String name) 
		this.name = name;
	



 

1.4.2   activity_main.xml布局

应用启动过渡阶段的时候显示

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.jie.socket.chat.MainActivity" >

</RelativeLayout>


 

1.4.3   MainActivity入口类

MainActivity入口,监测用户是否登陆状况,判断进入主界面还是进入登陆界面

package com.jie.socket.chat;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;

import com.jie.socket.chat.info.UserInfo;

/**
 * @ClassName:     MainActivity.java
 * @Description:   TODO(Activity入口,监测用户是否登陆状况,判断进入主界面还是进入登陆界面) 
 * @author         yangjie
 * @version        V1.0  
 * @Date           2016年5月25日 下午8:35:48
 */
public class MainActivity extends Activity 

	@Override
	protected void onCreate(Bundle savedInstanceState) 
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		checkLogin();
	

	/**
	 * @Title: checkLogin
	 * @Description: TODO(监测是否登陆)
	 * @return: void
	 * @throws
	 */
	public void checkLogin() 
		// TODO Auto-generated method stub
		UserInfo.readAll(getApplicationContext());
		String name = UserInfo.getInstance().getName();
		System.out.println("username:" + name);
		if (name != null && !"".equals(name)) 
			gotoNext();
		 else 
			gotoLogin();
		
	

	public void gotoLogin() 
		Intent intent = new Intent();
		intent.setClass(MainActivity.this, LoginActivity.class);
		intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
		startActivity(intent);
		finish();
	

	private void gotoNext() 
		Intent intent = new Intent();
		intent.setClass(MainActivity.this, ChatActivity.class);
		intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
		startActivity(intent);
		finish();
	



 

1.4.4   activity_chat.xml布局文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.jie.socket.chat.ChatActivity" >

    <LinearLayout
        android:id="@+id/layout_link"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <EditText
            android:id="@+id/et_ip"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="5"
            android:hint="请输入连接"
            android:text="192.168.0.199" />

        <Button
            android:id="@+id/btn_connect"
            android:layout_width="0dp"
            android:layout_height="30dp"
            android:layout_weight="2"
            android:background="@drawable/btn_selector"
            android:text="连接" />
    </LinearLayout>

    <TextView
        android:id="@+id/tv_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/layout_link"
        android:hint="消息" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="vertical" >

        <EditText
            android:id="@+id/et_msg"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="输入发送内容" />

        <Button
            android:id="@+id/btn_send"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:background="@drawable/btn_selector"
            android:text="发送" />
    </LinearLayout>

</RelativeLayout>

 

1.4.5   ChatActivity聊天类

通过socket连接服务器端,建立连接,然后通过socket接收和发送信息。

package com.jie.socket.chat;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import android.annotation.SuppressLint;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.alibaba.fastjson.JSONObject;
import com.jie.socket.chat.info.UserInfo;

/**
 * @ClassName: ChatActivity.java
 * @Description: TODO(聊天)
 * @author yangjie
 * @version V1.0
 * @Date 2016年5月25日 下午7:47:00
 */
public class ChatActivity extends BaseActivity 
	EditText et_ip;
	EditText et_msg;
	TextView tv_conent;
	Button btn_send;
	Button btn_connect;
	Socket socket;
	BufferedWriter writer;
	BufferedReader reader;
	String TAG = "Socket Chart";

	@Override
	protected void onCreate(Bundle savedInstanceState) 
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_chat);
		et_ip = (EditText) findViewById(R.id.et_ip);
		et_msg = (EditText) findViewById(R.id.et_msg);
		tv_conent = (TextView) findViewById(R.id.tv_content);
		btn_connect = (Button) findViewById(R.id.btn_connect);
		btn_send = (Button) findViewById(R.id.btn_send);
		btn_send.setEnabled(false);
		et_msg.setEnabled(false);
		eventListener();
	

	private void eventListener() 
		// TODO Auto-generated method stub
		btn_connect.setOnClickListener(new OnClickListener() 

			@Override
			public void onClick(View v) 
				// TODO Auto-generated method stub
				connnet();
			
		);
		btn_send.setOnClickListener(new OnClickListener() 

			@Override
			public void onClick(View v) 
				// TODO Auto-generated method stub
				send();
			
		);
		et_msg.setOnKeyListener(onKey);
	

	StringBuffer text = new StringBuffer();

	/**
	 * @Title: connnet
	 * @Description: TODO(连接)
	 * @return: void
	 * @throws
	 */
	private void connnet() 
		// TODO Auto-generated method stub
		read.execute();
	

	/**
	 * @Title: send
	 * @Description: TODO(发送消息)
	 * @return: void
	 * @throws
	 */
	private void send() 
		// TODO Auto-generated method stub
		try 
			String msg = et_msg.getText().toString();
			if (msg != null && !"".equals(msg)) 
				text.append(name + ":" + msg + "\\n");
				tv_conent.setText(text);
				// 传递给sokect服务,json数据name:1212,msg:'121212'
				JSONObject jsonObject = new JSONObject();
				jsonObject.put("name", name);
				jsonObject.put("msg", msg);
				writer.write(jsonObject.toString() + "\\n");
				writer.flush();// 刷新缓冲区,强制输出
				Log.i(TAG, msg);
				et_msg.setText("");
			 else 
				showToast("请输入发送内容");
			
		 catch (NullPointerException excNull) 
			Log.i(TAG, "writer error:" + "空指针异常");
			showToast("请点击连接,连接到服务器");
		 catch (Exception e) 
			// TODO Auto-generated catch block
			Log.i(TAG, "Error:" + e.getMessage());
			e.printStackTrace();
		
	

	@SuppressLint("ShowToast")
	public void showToast(String msg) 
		Toast.makeText(getApplicationContext(), msg, 1000).show();
	

	OnKeyListener onKey = new OnKeyListener() // 回车键监听

		@Override
		public boolean onKey(View v, int keyCode, KeyEvent event) 
			// 回车键,并且为鼠标按下,防止按下回车键两次调用
			if (keyCode == KeyEvent.KEYCODE_ENTER
					&& event.getAction() == KeyEvent.ACTION_DOWN) 
				Log.i(TAG, "回车键:" + keyCode);
				send();
				return true;
			
			return false;
		
	;
	OutputStreamWriter outputStreamWriter;
	InputStreamReader inputStreamReader;
	AsyncTask<Void, String, Void> read = new AsyncTask<Void, String, Void>() 

		@Override
		protected Void doInBackground(Void... params) 
			// TODO Auto-generated method stub
			try 
				socket = new Socket(et_ip.getText().toString().trim(), 12345);
				outputStreamWriter = new OutputStreamWriter(
						socket.getOutputStream());
				inputStreamReader = new InputStreamReader(
						socket.getInputStream());
				writer = new BufferedWriter(outputStreamWriter);
				reader = new BufferedReader(inputStreamReader);
				publishProgress("@success");
			 catch (UnknownHostException e) 
				// TODO Auto-generated catch block
				Log.i("socket", "连接失败");
				e.printStackTrace();
			 catch (IOException e) 
				// TODO Auto-generated catch block
				e.printStackTrace();
				// showToast("连接失败");
				Log.i("socket", "连接失败");
			
			String line;

			// 异步线程未关闭
			if (!isCancelled()) 
				while (true) 
					try 
						if ((line = reader.readLine()) != null) 
							publishProgress(line);
						
					 catch (IOException e) 
						// TODO Auto-generated catch block
						if ("Socket closed".equals(e.getMessage())) 
							Log.i(TAG, "连接已关闭");
						 else 
							e.printStackTrace();
						
						break;
					
				
			
			return null;
		

		@Override
		protected void onProgressUpdate(String... values) 
			// TODO Auto-generated method stub
			if (values[0] != null && !"".equals(values[0])) 
				if (values[0] == "@success") 
					// text.append(values[0]);
					btn_connect.setEnabled(false);
					Log.i(TAG, "连接服务器成功!");
					tv_conent.setText("连接服务器成功!");
					btn_send.setEnabled(true);
					et_msg.setEnabled(true);
					name = UserInfo.readName(getApplicationContext());
					if (name != null && !"".equals(name))
						;
					
						Log.i(TAG, "name:" + name);
						try 
							writer.write("name:" + name + "\\n");
							writer.flush();// 强制输出
						 catch (IOException e) 
							// TODO Auto-generated catch block
							e.printStackTrace();
						
					

				 else 
					JSONObject obj = JSONObject.parseObject(values[0]);// 将json字符串转换为对象
					String cName = obj.getString("name");
					String cMsg = obj.getString("msg");
					text.append(cName + ":" + cMsg + "\\n");
					Log.i(TAG, values[0]);
					tv_conent.setText(text);
				
			
		

	;

	@Override
	protected void onDestroy() 
		// TODO Auto-generated method stub
		super.onDestroy();
		// Log.i(TAG, "socket != null:"+(socket != null)
		// +"----socket.isClosed():"+(!socket.isClosed()));
		if (socket != null && !socket.isClosed()) 
			Log.i(TAG, "关闭连接");
			try 
				read.cancel(true);// 线程关闭
				socket.close();
				reader.close();
				writer.close();
			 catch (IOException e) 
				// TODO Auto-generated catch block
				e.printStackTrace();
			// 关闭连接
		
	



1.4.6   基础Activity

用于设置Activity公用的字段和方法。

package com.jie.socket.chat;

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Window;
import android.widget.Toast;

import com.jie.socket.chat.info.UserInfo;

public class BaseActivity extends Activity 
	String name;

	@Override
	protected void onCreate(Bundle savedInstanceState) 
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		initDatas();
	

	public void findViews() 

	

	public void initDatas() 
		name = UserInfo.readName(getApplicationContext());
	

	public void clickEvents() 

	

	@Override
	protected void onDestroy() 
		// TODO Auto-generated method stub
		super.onDestroy();
	

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) 
		// TODO Auto-generated method stub
		return super.onKeyDown(keyCode, event);
	

	@Override
	protected void onResume() 
		// TODO Auto-generated method stub
		super.onResume();
	

	@Override
	protected void onPause() 
		// TODO Auto-generated method stub
		super.onPause();

	

	@Override
	public void onBackPressed() 
		super.onBackPressed();
	

	public void showToast(CharSequence message) 
		if (message != null && !"".equals(message)) 
			Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT)
					.show();
		 else 
			Toast.makeText(getApplicationContext(), "连接超时,请检查网络",
					Toast.LENGTH_SHORT).show();
		
	



1.4.7   activity_login.xml登陆布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:background="@drawable/gb_background"
    android:gravity="center"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.jie.socket.chat.LoginActivity" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="用户名:"
            android:textSize="18px" />

        <EditText
            android:id="@+id/userName"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="3"
            android:textSize="18px" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="15dp"
        android:orientation="horizontal" >

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="密   码:"
            android:textSize="18px" />

        <EditText
            android:id="@+id/userPassword"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="3"
            android:password="true"
            android:textSize="18px" />
    </LinearLayout>

    <Button
        android:id="@+id/btn_login"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:background="@drawable/btn_selector"
        android:text="登陆" />

</LinearLayout>

 

1.4.8   LoginActivity登陆类

package com.jie.socket.chat;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

import com.jie.socket.chat.info.UserInfo;
import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.RequestParams;
import com.lidroid.xutils.http.ResponseInfo;
import com.lidroid.xutils.http.callback.RequestCallBack;
import com.lidroid.xutils.http.client.HttpRequest.HttpMethod;

public class LoginActivity extends BaseActivity 
	EditText et_userName;
	EditText et_userPassword;
	Button btn_login;
	String name;
	String password;
	protected String httpUrl = "http://192.168.0.199:8080/SocketChatServer/chatLogin";

	@Override
	protected void onCreate(Bundle savedInstanceState) 
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_login);
		et_userName = (EditText) findViewById(R.id.userName);
		et_userPassword = (EditText) findViewById(R.id.userPassword);
		btn_login = (Button) findViewById(R.id.btn_login);
		btn_login.setOnClickListener(new OnClickListener() 

			@Override
			public void onClick(View v) 
				// TODO Auto-generated method stub
				name = et_userName.getText().toString();
				password = et_userPassword.getText().toString();
				if (!"".equals(name) && !"".equals(password)) 
					HttpUtils http = new HttpUtils();
					RequestParams params = new RequestParams();
					params.addBodyParameter("name", name);
					params.addBodyParameter("password", password);
					http.send(HttpMethod.POST, httpUrl, params,
							new RequestCallBack<String>() 

								@Override
								public void onFailure(HttpException arg0,
										String arg1) 
									// TODO Auto-generated method stub
									Log.i("http.send", "failuer");

								

								@Override
								public void onSuccess(ResponseInfo<String> arg0) 
									// TODO Auto-generated method stub
									String isLogin = arg0.result;
									if ("true".equals(isLogin)) // 登陆成功
										Intent intent = new Intent();
										intent.setClass(LoginActivity.this,
												ChatActivity.class);
										intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
										startActivity(intent);
										finish();
										Log.i("http.send", "success" + isLogin);
										UserInfo.getInstance().setName(name);
										UserInfo.saveName(getApplicationContext());
									 else 
										showToast("用户名或密码错误");
									

								
							);
				
			
		);
	



 

1.5     源码下载

基于Socket的Android聊天室

 

 

以上是关于基于Socket的Android聊天室的主要内容,如果未能解决你的问题,请参考以下文章

基于Socket的Android聊天室

利用Socket制作一个简易的Android聊天室

在其他端口上使用 socket.io

基于java版聊天室的设计

基于Socket的网络聊天室

python基于socket和pyqt的简易聊天室