Android之Socket群组聊天
在这只做了一个简单的例子,没有用到数据库,思路就是客户端发送信息到服务器端,服务器端转发所有数据到客户端,校验服务器端发来消息是否是自己发出的,如果是自己发出的,则不显示自己的消息
- 贴一下Android客户端的源码 -
MainActivity.Java
- package com.zml.chatproject;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.support.v7.app.AppCompatActivity;
- import android.text.Editable;
- import android.text.TextUtils;
- import android.text.TextWatcher;
- import android.util.Log;
- import android.view.KeyEvent;
- import android.view.View;
- import android.view.WindowManager;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.ListView;
- import android.widget.Toast;
- import com.google.gson.Gson;
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.IOException;
- import java.net.Socket;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * @author 郑明亮 @email 1072307340@qq.com
- * @Time:2016/4/20 14:25
- * @version 1.0
- * TODO
- */
- public class MainActivity extends AppCompatActivity implements View.OnClickListener, TextWatcher {
- private static final String TAG = "MainActivity";
- public static final int SENDMESSAGE = 0x004;
- public static final String name = System.currentTimeMillis()+"";
- List<Msg> list ;
- ListView mListView;
- EditText edit;
- Button bt_send;
- Socket socket;
- public static final int SHOWMSG = 0x003;
- private DataInputStream mDataInputStream = null;
- private DataOutputStream mDataOutputStream = null;
- private boolean Conneted = false;
- Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- Log.i(TAG,"执行到handle");
- if (msg.what == SENDMESSAGE) {
- Msg xiaoxi = (Msg) msg.obj;
- Log.i(TAG,"handler:"+xiaoxi.toString());
- list.add(xiaoxi);
- //设置适配器
- mListView.setAdapter(new MyAdapter(MainActivity.this, list));
- mListView.setSelection(mListView.getCount()-1);
- }
- }
- };
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mListView = (ListView) findViewById(R.id.listView);
- edit = (EditText) findViewById(R.id.et_edit);
- edit.addTextChangedListener(this);
- bt_send = (Button) findViewById(R.id.bt_send);
- bt_send.setOnClickListener(this);
- list = new ArrayList<>();
- new AsyncTask<Void,Void,String>(){
- @Override
- protected String doInBackground(Void... params) {
- try {
- socket = new Socket("172.18.40.182", 9999);
- // socket = new Socket("115.28.167.152", 9999);
- connect();
- ClientThread thread = new ClientThread();
- thread.run();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
- }.execute();
- }
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- switch (event.getAction()){
- case KeyEvent.KEYCODE_HOME:
- Toast.makeText(MainActivity.this,"就是不让你退出,O(∩_∩)O哈哈哈~",Toast.LENGTH_LONG).show();
- Log.i(TAG,"KeyEvent.KEYCODE_HOME"+KeyEvent.KEYCODE_HOME);
- break;
- case KeyEvent.KEYCODE_MOVE_HOME:
- Toast.makeText(MainActivity.this,"就是不让你退出,O(∩_∩)O哈哈哈~",Toast.LENGTH_LONG).show();
- Log.i(TAG,"KeyEvent.KEYCODE_MOVE_HOME"+KeyEvent.KEYCODE_MOVE_HOME);
- break;
- }
- return true;
- }
- @Override
- public void onAttachedToWindow()
- { // TODO Auto-generated method stub
- this.getWindow().setType(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
- super.onAttachedToWindow();
- }
- @Override
- public void onClick(View v) {
- switch (v.getId()){
- case R.id.bt_send:
- String show = edit.getText().toString().trim();
- if (TextUtils.isEmpty(show)){
- }else {
- edit.setText("");
- Msg msg = new Msg();
- msg.setFlag(Msg.TO);
- msg.setMsg(show);
- msg.setUsername(name);
- list.add(msg);
- mListView.setAdapter(new MyAdapter(MainActivity.this,list));
- mListView.setSelection(mListView.getCount()-1);
- try {if (mDataOutputStream==null){
- mDataOutputStream = new DataOutputStream(socket.getOutputStream());
- }
- Gson gson = new Gson();
- show = gson.toJson(msg);
- mDataOutputStream.writeUTF(show);
- mDataOutputStream.flush();
- Log.i(TAG,"发送成功:"+show);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- break;
- }
- }
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- bt_send.setEnabled(false);
- }
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- if (s.length()>0){
- bt_send.setEnabled(true);
- }
- }
- @Override
- public void afterTextChanged(Editable s) {
- }
- /**
- * 开启线程,接收消息
- */
- private class ClientThread implements Runnable {
- @Override
- public void run() {
- while (Conneted) {
- try {
- String str = mDataInputStream.readUTF();
- Log.i(TAG,"子线程得到数据:"+str);
- Gson gson = new Gson();
- Msg msg = gson.fromJson(str,Msg.class);
- msg.setFlag(Msg.FROM);
- Message message = mHandler.obtainMessage();
- message.what = SENDMESSAGE;
- message.obj = msg;
- mHandler.sendMessage(message);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- /**
- * 打开连接
- */
- public void connect() {
- try {
- mDataInputStream = new DataInputStream(socket.getInputStream());
- mDataOutputStream = new DataOutputStream(socket.getOutputStream());
- if (socket.isConnected()){
- Log.i(TAG, "连接上了");
- }else {
- Log.i(TAG, "连接失败");
- }
- Conneted = true;
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- /**
- * 断开与服务器的连接
- */
- public void disconnect() {
- try {
- mDataInputStream.close();
- mDataOutputStream.close();
- socket.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- disconnect();
- }
- }
Msg.java 消息实体类
- package com.zml.chatproject;
- /**
- * Created by bri on 2016/4/16.
- */
- /**
- * 消息实体类
- */
- public class Msg {
- public static final int FROM = 0x001;
- public static final int TO = 0x002;
- /**
- * 发送聊天消息
- */
- private String msg;
- /**
- * 标识符,表示是发送方还是接收方
- */
- private int flag;
- /**
- * 用户名
- */
- private String username;
- @Override
- public String toString() {
- return "Msg{" +
- "msg='" + msg + '\\'' +
- ", flag=" + flag +
- ", username='" + username + '\\'' +
- '}';
- }
- public String getMsg() {
- return msg;
- }
- public void setMsg(String msg) {
- this.msg = msg;
- }
- public int getFlag() {
- return flag;
- }
- public void setFlag(int flag) {
- this.flag = flag;
- }
- public String getUsername() {
- return username;
- }
- public void setUsername(String username) {
- this.username = username;
- }
- }
MyAdapter 数据适配器
- package com.zml.chatproject;
- import android.content.Context;
- import android.util.Log;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- import android.widget.ListAdapter;
- import android.widget.TextView;
- import java.util.List;
- /**
- * Created by bri on 2016/4/17.
- */
- public class MyAdapter extends BaseAdapter implements ListAdapter {
- private static final String TAG = "MyAdapter";
- Context context;
- List<Msg> message;
- public MyAdapter(Context context, List<Msg> message) {
- this.context = context;
- this.message = message;
- }
- @Override
- public int getCount() {
- return message.size();
- }
- @Override
- public Object getItem(int position) {
- return null;
- }
- @Override
- public long getItemId(int position) {
- return 0;
- }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- if (convertView == null){
- convertView = LayoutInflater.from(context).inflate(R.layout.activity_main_item,null);
- }
- TextView tv_from = ViewHolder.get(convertView,R.id.tv_chatting_from);
- TextView tv_to = ViewHolder.get(convertView,R.id.tv_chatting_to);
- // tv_from.setText(message.getMsg());
- Log.i(TAG,"接收成功"+message.get(position).getMsg());
- if (message.get(position).getFlag()==(Msg.FROM)){
- if (message.get(position).getUsername().equals(MainActivity.name)){
- tv_from.setVisibility(View.GONE);
- tv_to.setVisibility(View.GONE);}
- else { Log.i(TAG,"接收成功FROM"+message.get(position).getMsg());
- tv_from.setText(message.get(position).getMsg());
- tv_from.setVisibility(View.VISIBLE);
- tv_to.setVisibility(View.GONE);}
- // Toast.makeText(context,"from:"+message.get(position).getMsg(),Toast.LENGTH_LONG).show();
- }if (message.get(position).getFlag()==(Msg.TO)){
- // Toast.makeText(context,"to:"+message.get(position).getMsg(),Toast.LENGTH_LONG).show();
- Log.i(TAG,"接收成功TO"+message.get(position).getMsg());
- tv_to.setText(message.get(position).getMsg());
- tv_from.setVisibility(View.GONE);
- tv_to.setVisibility(View.VISIBLE);
- }
- return convertView;
- }
- }
ViewHoder 一个超实用的通用ViewHoder类
- package com.zml.chatproject;
- import android.content.Context;
- import android.util.Log;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- import android.widget.ListAdapter;
- import android.widget.TextView;
- import java.util.List;
- /**
- * Created by bri on 2016/4/17.
- */
- public class MyAdapter extends BaseAdapter implements ListAdapter {
- private static final String TAG = "MyAdapter";
- Context context;
- List<Msg> message;
- public MyAdapter(Context context, List<Msg> message) {
- this.context = context;
- this.message = message;
- }
- @Override
- public int getCount() {
- return message.size();
- }
- @Override
- public Object getItem(int position) {
- return null;
- }
- @Override
- public long getItemId(int position) {
- return 0;
- }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- if (convertView == null){
- convertView = LayoutInflater.from(context).inflate(R.layout.activity_main_item,null);
- }
- TextView tv_from = ViewHolder.get(convertView,R.id.tv_chatting_from);
- TextView tv_to = ViewHolder.get(convertView,R.id.tv_chatting_to);
- // tv_from.setText(message.getMsg());
- Log.i(TAG,"接收成功"+message.get(position).getMsg());
- if (message.get(position).getFlag()==(Msg.FROM)){
- if (message.get(position).getUsername().equals(MainActivity.name)){
- tv_from.setVisibility(View.GONE);
- tv_to.setVisibility(View.GONE);}
- else { Log.i(TAG,"接收成功FROM"+message.get(position).getMsg());
- tv_from.setText(message.get(position).getMsg());
- tv_from.setVisibility(View.VISIBLE);
- tv_to.setVisibility(View.GONE);}
- // Toast.makeText(context,"from:"+message.get(position).getMsg(),Toast.LENGTH_LONG).show();
- }if (message.get(position).getFlag()==(Msg.TO)){
- // Toast.makeText(context,"to:"+message.get(position).getMsg(),Toast.LENGTH_LONG).show();
- Log.i(TAG,"接收成功TO"+message.get(position).getMsg());
- tv_to.setText(message.get(position).getMsg());
- tv_from.setVisibility(View.GONE);
- tv_to.setVisibility(View.VISIBLE);
- }
- return convertView;
- }
- }
- 好了,客户端的源码贴完了,接下来服务器端的源码就比较简单了
Client.java 重写一个子线程
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.IOException;
- import java.net.Socket;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.Iterator;
- import java.util.List;
- /**
- * @author 郑明亮
- * @Time:2016年4月16日 下午9:01:53
- * @version 1.0
- */
- public class Client implements Runnable {
- Socket socket;
- List<Client> clients ;
- public static final int SHOWMSG = 0x003;
- private DataInputStream mDataInputStream = null;
- private DataOutputStream mDataOutputStream = null;
- private boolean Conneted = false;
- public Client(Socket socket){
- this.socket = socket;
- try {
- mDataInputStream = new DataInputStream(socket.getInputStream());
- mDataOutputStream = new DataOutputStream(socket.getOutputStream());
- Conneted = true;
- clients =new ArrayList<Client>();
- } catch (IOException e) {
- e.printStackTrace();
- }
- };
- /**
- * 发送消息
- */
- public void send(String string){
- try {
- mDataOutputStream.writeUTF(string);//向输入流中写入数据
- System.out.println("向输入流中写入数据");
- } catch (IOException e) {
- e.printStackTrace();
- // Server.clients.remove(this);//出错时,客户端可能已断线,移除当前客户端
- System.out.println("出错时,客户端可能已断线,移除当前客户端");
- }
- }
- @Override
- public void run() {
- while(Conneted){
- try {
- System.out.println("连接成功!");
- //读取数据
- String str = mDataInputStream.readUTF();
- clients = Server.clients;
- synchronized (clients) {
- Iterator<Client> iterator =clients.iterator();
- while (iterator.hasNext()) {
- Client client = iterator.next();
- //将读取的数据发送回去
- System.out.println("将读取的数据发送回去"+str);
- client.send(str);
- }
- // Conneted = false;
- }
- } catch (IOException e) {
- e.printStackTrace();
- Server.clients.remove(this);
- System.out.println("线程出现异常");
- }finally{
- // try {
- //// mDataOutputStream.close();
- //// mDataInputStream.close();
- // } catch (IOException e) {
- // // TODO Auto-generated catch block
- // e.printStackTrace();
- // }
- }
- }
- }
- }
Server 服务器端,先运行起它来,再去部署客户端即可
- import java.io.IOException;
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.List;
- /**
- * @author 郑明亮
- * @Time:2016年4月16日 下午9:01:43
- * @version 1.0
- */
- public class Server {
- static boolean started = false;
- public static List<Client> clients = new ArrayList<>();
- public static void main(String a[]){
- try {
- ServerSocket serverSocket = new ServerSocket(9999);
- System.out.println("开启服务,等待监听");
- started = true;
- while (started) {
- System.out.println("开始监听");
- Socket socket = serverSocket.accept();
- Client client = new Client(socket);
- new Thread(client).start();
- clients.add(client);
- }
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
失败是什么?没有什么,只是更走近成功一步;成功是什么?就是走过了所有通向失败的路,只剩下一条路,那就是成功的路。