在这只做了一个简单的例子,没有用到数据库,思路就是客户端发送信息到服务器端,服务器端转发所有数据到客户端,校验服务器端发来消息是否是自己发出的,如果是自己发出的,则不显示自己的消息

  • 贴一下Android客户端的源码 -

    MainActivity.Java

  1. package com.zml.chatproject;
  2. import android.os.AsyncTask;
  3. import android.os.Bundle;
  4. import android.os.Handler;
  5. import android.os.Message;
  6. import android.support.v7.app.AppCompatActivity;
  7. import android.text.Editable;
  8. import android.text.TextUtils;
  9. import android.text.TextWatcher;
  10. import android.util.Log;
  11. import android.view.KeyEvent;
  12. import android.view.View;
  13. import android.view.WindowManager;
  14. import android.widget.Button;
  15. import android.widget.EditText;
  16. import android.widget.ListView;
  17. import android.widget.Toast;
  18. import com.google.gson.Gson;
  19. import java.io.DataInputStream;
  20. import java.io.DataOutputStream;
  21. import java.io.IOException;
  22. import java.net.Socket;
  23. import java.util.ArrayList;
  24. import java.util.List;
  25. /**
  26. * @author 郑明亮   @email 1072307340@qq.com
  27. * @Time:2016/4/20 14:25
  28. * @version 1.0
  29. * TODO
  30. */
  31. public class MainActivity extends AppCompatActivity implements View.OnClickListener, TextWatcher {
  32. private static final String TAG = "MainActivity";
  33. public static final int SENDMESSAGE = 0x004;
  34. public static final String name = System.currentTimeMillis()+"";
  35. List<Msg> list ;
  36. ListView mListView;
  37. EditText edit;
  38. Button bt_send;
  39. Socket socket;
  40. public static final int SHOWMSG = 0x003;
  41. private DataInputStream mDataInputStream = null;
  42. private DataOutputStream mDataOutputStream = null;
  43. private boolean Conneted = false;
  44. Handler mHandler = new Handler() {
  45. @Override
  46. public void handleMessage(Message msg) {
  47. super.handleMessage(msg);
  48. Log.i(TAG,"执行到handle");
  49. if (msg.what == SENDMESSAGE) {
  50. Msg xiaoxi = (Msg) msg.obj;
  51. Log.i(TAG,"handler:"+xiaoxi.toString());
  52. list.add(xiaoxi);
  53. //设置适配器
  54. mListView.setAdapter(new MyAdapter(MainActivity.this, list));
  55. mListView.setSelection(mListView.getCount()-1);
  56. }
  57. }
  58. };
  59. @Override
  60. protected void onCreate(Bundle savedInstanceState) {
  61. super.onCreate(savedInstanceState);
  62. setContentView(R.layout.activity_main);
  63. mListView = (ListView) findViewById(R.id.listView);
  64. edit = (EditText) findViewById(R.id.et_edit);
  65. edit.addTextChangedListener(this);
  66. bt_send = (Button) findViewById(R.id.bt_send);
  67. bt_send.setOnClickListener(this);
  68. list = new ArrayList<>();
  69. new AsyncTask<Void,Void,String>(){
  70. @Override
  71. protected String doInBackground(Void... params) {
  72. try {
  73. socket = new Socket("172.18.40.182", 9999);
  74. //               socket = new Socket("115.28.167.152", 9999);
  75. connect();
  76. ClientThread thread = new ClientThread();
  77. thread.run();
  78. } catch (IOException e) {
  79. e.printStackTrace();
  80. }
  81. return null;
  82. }
  83. }.execute();
  84. }
  85. @Override
  86. public boolean onKeyDown(int keyCode, KeyEvent event) {
  87. switch (event.getAction()){
  88. case KeyEvent.KEYCODE_HOME:
  89. Toast.makeText(MainActivity.this,"就是不让你退出,O(∩_∩)O哈哈哈~",Toast.LENGTH_LONG).show();
  90. Log.i(TAG,"KeyEvent.KEYCODE_HOME"+KeyEvent.KEYCODE_HOME);
  91. break;
  92. case KeyEvent.KEYCODE_MOVE_HOME:
  93. Toast.makeText(MainActivity.this,"就是不让你退出,O(∩_∩)O哈哈哈~",Toast.LENGTH_LONG).show();
  94. Log.i(TAG,"KeyEvent.KEYCODE_MOVE_HOME"+KeyEvent.KEYCODE_MOVE_HOME);
  95. break;
  96. }
  97. return true;
  98. }
  99. @Override
  100. public void onAttachedToWindow()
  101. { // TODO Auto-generated method stub
  102. this.getWindow().setType(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
  103. super.onAttachedToWindow();
  104. }
  105. @Override
  106. public void onClick(View v) {
  107. switch (v.getId()){
  108. case R.id.bt_send:
  109. String show = edit.getText().toString().trim();
  110. if (TextUtils.isEmpty(show)){
  111. }else {
  112. edit.setText("");
  113. Msg msg = new Msg();
  114. msg.setFlag(Msg.TO);
  115. msg.setMsg(show);
  116. msg.setUsername(name);
  117. list.add(msg);
  118. mListView.setAdapter(new MyAdapter(MainActivity.this,list));
  119. mListView.setSelection(mListView.getCount()-1);
  120. try {if (mDataOutputStream==null){
  121. mDataOutputStream = new DataOutputStream(socket.getOutputStream());
  122. }
  123. Gson gson = new Gson();
  124. show =  gson.toJson(msg);
  125. mDataOutputStream.writeUTF(show);
  126. mDataOutputStream.flush();
  127. Log.i(TAG,"发送成功:"+show);
  128. } catch (IOException e) {
  129. e.printStackTrace();
  130. }
  131. }
  132. break;
  133. }
  134. }
  135. @Override
  136. public void beforeTextChanged(CharSequence s, int start, int count, int after) {
  137. bt_send.setEnabled(false);
  138. }
  139. @Override
  140. public void onTextChanged(CharSequence s, int start, int before, int count) {
  141. if (s.length()>0){
  142. bt_send.setEnabled(true);
  143. }
  144. }
  145. @Override
  146. public void afterTextChanged(Editable s) {
  147. }
  148. /**
  149. * 开启线程,接收消息
  150. */
  151. private class ClientThread implements Runnable {
  152. @Override
  153. public void run() {
  154. while (Conneted) {
  155. try {
  156. String str = mDataInputStream.readUTF();
  157. Log.i(TAG,"子线程得到数据:"+str);
  158. Gson gson = new Gson();
  159. Msg msg = gson.fromJson(str,Msg.class);
  160. msg.setFlag(Msg.FROM);
  161. Message message = mHandler.obtainMessage();
  162. message.what = SENDMESSAGE;
  163. message.obj = msg;
  164. mHandler.sendMessage(message);
  165. } catch (IOException e) {
  166. e.printStackTrace();
  167. }
  168. }
  169. }
  170. }
  171. /**
  172. * 打开连接
  173. */
  174. public void connect() {
  175. try {
  176. mDataInputStream = new DataInputStream(socket.getInputStream());
  177. mDataOutputStream = new DataOutputStream(socket.getOutputStream());
  178. if (socket.isConnected()){
  179. Log.i(TAG, "连接上了");
  180. }else {
  181. Log.i(TAG, "连接失败");
  182. }
  183. Conneted = true;
  184. } catch (IOException e) {
  185. e.printStackTrace();
  186. }
  187. }
  188. /**
  189. * 断开与服务器的连接
  190. */
  191. public void disconnect() {
  192. try {
  193. mDataInputStream.close();
  194. mDataOutputStream.close();
  195. socket.close();
  196. } catch (IOException e) {
  197. e.printStackTrace();
  198. }
  199. }
  200. @Override
  201. protected void onDestroy() {
  202. super.onDestroy();
  203. disconnect();
  204. }
  205. }

Msg.java 消息实体类

  1. package com.zml.chatproject;
  2. /**
  3. * Created by bri on 2016/4/16.
  4. */
  5. /**
  6. * 消息实体类
  7. */
  8. public class Msg {
  9. public static final int FROM = 0x001;
  10. public static final int TO = 0x002;
  11. /**
  12. * 发送聊天消息
  13. */
  14. private String msg;
  15. /**
  16. * 标识符,表示是发送方还是接收方
  17. */
  18. private int flag;
  19. /**
  20. * 用户名
  21. */
  22. private String username;
  23. @Override
  24. public String toString() {
  25. return "Msg{" +
  26. "msg='" + msg + '\\'' +
  27. ", flag=" + flag +
  28. ", username='" + username + '\\'' +
  29. '}';
  30. }
  31. public String getMsg() {
  32. return msg;
  33. }
  34. public void setMsg(String msg) {
  35. this.msg = msg;
  36. }
  37. public int getFlag() {
  38. return flag;
  39. }
  40. public void setFlag(int flag) {
  41. this.flag = flag;
  42. }
  43. public String getUsername() {
  44. return username;
  45. }
  46. public void setUsername(String username) {
  47. this.username = username;
  48. }
  49. }

MyAdapter 数据适配器

  1. package com.zml.chatproject;
  2. import android.content.Context;
  3. import android.util.Log;
  4. import android.view.LayoutInflater;
  5. import android.view.View;
  6. import android.view.ViewGroup;
  7. import android.widget.BaseAdapter;
  8. import android.widget.ListAdapter;
  9. import android.widget.TextView;
  10. import java.util.List;
  11. /**
  12. * Created by bri on 2016/4/17.
  13. */
  14. public class MyAdapter extends BaseAdapter implements ListAdapter {
  15. private static final String TAG = "MyAdapter";
  16. Context context;
  17. List<Msg> message;
  18. public MyAdapter(Context context, List<Msg> message) {
  19. this.context = context;
  20. this.message = message;
  21. }
  22. @Override
  23. public int getCount() {
  24. return message.size();
  25. }
  26. @Override
  27. public Object getItem(int position) {
  28. return null;
  29. }
  30. @Override
  31. public long getItemId(int position) {
  32. return 0;
  33. }
  34. @Override
  35. public View getView(int position, View convertView, ViewGroup parent) {
  36. if (convertView == null){
  37. convertView = LayoutInflater.from(context).inflate(R.layout.activity_main_item,null);
  38. }
  39. TextView tv_from = ViewHolder.get(convertView,R.id.tv_chatting_from);
  40. TextView tv_to = ViewHolder.get(convertView,R.id.tv_chatting_to);
  41. //        tv_from.setText(message.getMsg());
  42. Log.i(TAG,"接收成功"+message.get(position).getMsg());
  43. if (message.get(position).getFlag()==(Msg.FROM)){
  44. if (message.get(position).getUsername().equals(MainActivity.name)){
  45. tv_from.setVisibility(View.GONE);
  46. tv_to.setVisibility(View.GONE);}
  47. else { Log.i(TAG,"接收成功FROM"+message.get(position).getMsg());
  48. tv_from.setText(message.get(position).getMsg());
  49. tv_from.setVisibility(View.VISIBLE);
  50. tv_to.setVisibility(View.GONE);}
  51. //            Toast.makeText(context,"from:"+message.get(position).getMsg(),Toast.LENGTH_LONG).show();
  52. }if (message.get(position).getFlag()==(Msg.TO)){
  53. //            Toast.makeText(context,"to:"+message.get(position).getMsg(),Toast.LENGTH_LONG).show();
  54. Log.i(TAG,"接收成功TO"+message.get(position).getMsg());
  55. tv_to.setText(message.get(position).getMsg());
  56. tv_from.setVisibility(View.GONE);
  57. tv_to.setVisibility(View.VISIBLE);
  58. }
  59. return convertView;
  60. }
  61. }

ViewHoder 一个超实用的通用ViewHoder类

  1. package com.zml.chatproject;
  2. import android.content.Context;
  3. import android.util.Log;
  4. import android.view.LayoutInflater;
  5. import android.view.View;
  6. import android.view.ViewGroup;
  7. import android.widget.BaseAdapter;
  8. import android.widget.ListAdapter;
  9. import android.widget.TextView;
  10. import java.util.List;
  11. /**
  12. * Created by bri on 2016/4/17.
  13. */
  14. public class MyAdapter extends BaseAdapter implements ListAdapter {
  15. private static final String TAG = "MyAdapter";
  16. Context context;
  17. List<Msg> message;
  18. public MyAdapter(Context context, List<Msg> message) {
  19. this.context = context;
  20. this.message = message;
  21. }
  22. @Override
  23. public int getCount() {
  24. return message.size();
  25. }
  26. @Override
  27. public Object getItem(int position) {
  28. return null;
  29. }
  30. @Override
  31. public long getItemId(int position) {
  32. return 0;
  33. }
  34. @Override
  35. public View getView(int position, View convertView, ViewGroup parent) {
  36. if (convertView == null){
  37. convertView = LayoutInflater.from(context).inflate(R.layout.activity_main_item,null);
  38. }
  39. TextView tv_from = ViewHolder.get(convertView,R.id.tv_chatting_from);
  40. TextView tv_to = ViewHolder.get(convertView,R.id.tv_chatting_to);
  41. //        tv_from.setText(message.getMsg());
  42. Log.i(TAG,"接收成功"+message.get(position).getMsg());
  43. if (message.get(position).getFlag()==(Msg.FROM)){
  44. if (message.get(position).getUsername().equals(MainActivity.name)){
  45. tv_from.setVisibility(View.GONE);
  46. tv_to.setVisibility(View.GONE);}
  47. else { Log.i(TAG,"接收成功FROM"+message.get(position).getMsg());
  48. tv_from.setText(message.get(position).getMsg());
  49. tv_from.setVisibility(View.VISIBLE);
  50. tv_to.setVisibility(View.GONE);}
  51. //            Toast.makeText(context,"from:"+message.get(position).getMsg(),Toast.LENGTH_LONG).show();
  52. }if (message.get(position).getFlag()==(Msg.TO)){
  53. //            Toast.makeText(context,"to:"+message.get(position).getMsg(),Toast.LENGTH_LONG).show();
  54. Log.i(TAG,"接收成功TO"+message.get(position).getMsg());
  55. tv_to.setText(message.get(position).getMsg());
  56. tv_from.setVisibility(View.GONE);
  57. tv_to.setVisibility(View.VISIBLE);
  58. }
  59. return convertView;
  60. }
  61. }
  • 好了,客户端的源码贴完了,接下来服务器端的源码就比较简单了

Client.java 重写一个子线程

  1. import java.io.DataInputStream;
  2. import java.io.DataOutputStream;
  3. import java.io.IOException;
  4. import java.net.Socket;
  5. import java.util.ArrayList;
  6. import java.util.Collections;
  7. import java.util.Iterator;
  8. import java.util.List;
  9. /**
  10. * @author 郑明亮
  11. * @Time:2016年4月16日 下午9:01:53
  12. * @version 1.0
  13. */
  14. public class Client implements  Runnable {
  15. Socket socket;
  16. List<Client> clients  ;
  17. public static final int SHOWMSG = 0x003;
  18. private DataInputStream mDataInputStream = null;
  19. private DataOutputStream mDataOutputStream = null;
  20. private boolean Conneted = false;
  21. public Client(Socket socket){
  22. this.socket = socket;
  23. try {
  24. mDataInputStream = new DataInputStream(socket.getInputStream());
  25. mDataOutputStream = new DataOutputStream(socket.getOutputStream());
  26. Conneted = true;
  27. clients =new ArrayList<Client>();
  28. } catch (IOException e) {
  29. e.printStackTrace();
  30. }
  31. };
  32. /**
  33. * 发送消息
  34. */
  35. public void send(String string){
  36. try {
  37. mDataOutputStream.writeUTF(string);//向输入流中写入数据
  38. System.out.println("向输入流中写入数据");
  39. } catch (IOException e) {
  40. e.printStackTrace();
  41. //            Server.clients.remove(this);//出错时,客户端可能已断线,移除当前客户端
  42. System.out.println("出错时,客户端可能已断线,移除当前客户端");
  43. }
  44. }
  45. @Override
  46. public void run() {
  47. while(Conneted){
  48. try {
  49. System.out.println("连接成功!");
  50. //读取数据
  51. String str = mDataInputStream.readUTF();
  52. clients = Server.clients;
  53. synchronized (clients) {
  54. Iterator<Client> iterator =clients.iterator();
  55. while (iterator.hasNext()) {
  56. Client client = iterator.next();
  57. //将读取的数据发送回去
  58. System.out.println("将读取的数据发送回去"+str);
  59. client.send(str);
  60. }
  61. //                Conneted = false;
  62. }
  63. } catch (IOException e) {
  64. e.printStackTrace();
  65. Server.clients.remove(this);
  66. System.out.println("线程出现异常");
  67. }finally{
  68. //            try {
  69. ////                mDataOutputStream.close();
  70. ////                mDataInputStream.close();
  71. //            } catch (IOException e) {
  72. //                // TODO Auto-generated catch block
  73. //                e.printStackTrace();
  74. //            }
  75. }
  76. }
  77. }
  78. }

Server 服务器端,先运行起它来,再去部署客户端即可

  1. import java.io.IOException;
  2. import java.net.ServerSocket;
  3. import java.net.Socket;
  4. import java.util.ArrayList;
  5. import java.util.Collections;
  6. import java.util.List;
  7. /**
  8. * @author 郑明亮
  9. * @Time:2016年4月16日 下午9:01:43
  10. * @version 1.0
  11. */
  12. public class Server {
  13. static boolean started = false;
  14. public static List<Client> clients = new ArrayList<>();
  15. public static void main(String a[]){
  16. try {
  17. ServerSocket serverSocket = new ServerSocket(9999);
  18. System.out.println("开启服务,等待监听");
  19. started = true;
  20. while (started) {
  21. System.out.println("开始监听");
  22. Socket socket = serverSocket.accept();
  23. Client client = new Client(socket);
  24. new Thread(client).start();
  25. clients.add(client);
  26. }
  27. } catch (IOException e) {
  28. // TODO Auto-generated catch block
  29. e.printStackTrace();
  30. }
  31. }
  32. }

Android之Socket群组聊天的更多相关文章

  1. Android 内置群组,联系人

    这样一个需求,手机第一次启动的时候,需要内置一个群组,并且里面有给定的联系人信息, 本来打算写双进程守护的,结果昨天接到一个这样的任务,就先把它做了,发现里面有些操作数据库的东西还是值得看一下. 首先 ...

  2. vue-cli3.0 Typescript 项目集成环信WebIM 群组聊天

    项目背景 环信webim 官方没有vue版本的,自己就根据sdk重写了个vue版本的,只实现了基础的 登录 群组功能,其他的可以根据需要参考官方文档,添加相应的功能. 环信webim SDK相关文档: ...

  3. ASP.NET SignalR 系列(五)之群组推送

    在上一章介绍了 一对一推送的方式,这章重点介绍下群组推送和多人推送 群组主要就是用到了方法:Groups.Add(Context.ConnectionId, groupName); 将不同的连接id加 ...

  4. nodejs之socket.io 私发消息和选择群组发消息

    写在前面:其实有的时候忙碌是好的,比如忙碌起来的自己手机可以一天耗费掉只有20%的电,忙碌的自己很专心于一件事情,但是忙碌不等于过度疲劳,本周忙碌有点上脑,迷糊了一天,都在补觉,还是要去平衡下自己一天 ...

  5. Android 基于Socket的聊天应用(二)

    很久没写BLOG了,之前在写Android聊天室的时候答应过要写一个客户(好友)之间的聊天demo,Android 基于Socket的聊天室已经实现了通过Socket广播形式的通信功能. 以下是我写的 ...

  6. java ssm 后台框架平台 项目源码 websocket即时聊天发图片文字 好友群组 SSM源码

    官网 http://www.fhadmin.org/D 集成安全权限框架shiro  Shiro 是一个用 Java 语言实现的框架,通过一个简单易用的 API 提供身份验证和授权,更安全,更可靠E ...

  7. Activiti6.0 工作流引擎 websocket即时聊天发图片文字 好友群组 SSM源码

    即时通讯:支持好友,群组,发图片.文件,消息声音提醒,离线消息,保留聊天记录 (即时聊天功能支持手机端,详情下面有截图) 工作流模块---------------------------------- ...

  8. java工作流引擎 Activiti6.0 websocket 即时聊天发图片文字 好友群组 SSM源码

    时通讯:支持好友,群组,发图片.文件,消息声音提醒,离线消息,保留聊天记录 工作流模块--------------------------------------------------------- ...

  9. Android/iOS微信6.3.5同时发布更新 支持群视频聊天、群公告

    下午微信6.3.5发布更新,新版最大变化就是支持群视频聊天,又一次向手机QQ靠拢.在群管理方面,支持发布群公告,支持群主转让给其他群成员,同样都是QQ玩剩下的功能.另外,新版支持微信运动查看步数图表. ...

随机推荐

  1. Linux静态库和动态库

    Linux 工具 ❑ GCC: The GNU Compiler Collection, containing the GNU C compiler❑ G++: A C++ compiler, inc ...

  2. redhat6修改主机名

    1.临时修改主机名 sudo hostname lyhost 2.永久修改主机名 vim /etc/sysconfig/network 修改里面的hostname字段即可,重启后生效.

  3. 安卓RadioButton的使用

    学习目的: 1.掌握在Android中如何建立RadioGroup和RadioButton 2.掌握RadioGroup的常用属性 3.理解RadioButton和CheckBox的区别 4.掌握Ra ...

  4. 什么是A股、B股、H股、蓝筹股、红筹股

    A股 A股的正式名称是人民币普通股票.它是由我同境内的公司发行,供境内机构.组织或个人(不含台.港.澳投资者)以人民币认购和交易的普通股股票,我国A股股票市场经过几年快速发展,已经初具规模. B股 B ...

  5. 本博客不再更新,欢迎访问本人托管在GitHub上的博客:www.wshunli.com

    本博客不再更新. 欢迎访问本人托管在GitHub上的博客:www.wshunli.com

  6. CentOS7安装配置FTP服务器

    假设我们有以下要求 路径 权限 备注 /ftp/open 公司所有人员包括来宾均可以访问 只读 /ftp/private 仅允许Alice.Jack.Tom三个人访问 Alice.Jack只允许下载, ...

  7. CentOS 加载/挂载 U盘

    1.以root用户登陆   先加载USB模块 modprobe usb-storage    用fdisk -l 看看U盘的设备   假如U盘是sda1 2.确定在 目录 /mnt 下建立了 文件夹 ...

  8. Linux系统安装MySQL步骤及支持远程操作配置方法

    一.数据库安装(安装在/usr/local目录) 1. 压缩包拷贝到/users/lengyufang/tools 2. groupadd mysql3. useradd -r -g mysql -s ...

  9. Docker基础技术:AUFS

    AUFS是一种Union File System,所谓UnionFS就是把不同物理位置的目录合并mount到同一个目录中.UnionFS的一个最主要的应用是,把一张CD/DVD和一个硬盘目录给联合 m ...

  10. 卷积神经网络和CIFAR-10:Yann LeCun专访 Convolutional Nets and CIFAR-10: An Interview with Yann LeCun

    Recently Kaggle hosted a competition on the CIFAR-10 dataset. The CIFAR-10 dataset consists of 60k 3 ...