您的位置:首页 > 移动开发 > Android开发

Android之Socket群组聊天

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

项目源码下载

贴一下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.util.SparseArray;
import android.view.View;

/**
* Created by bri on 2016/4/17.
*/
public class ViewHolder {
// I added a generic return type to reduce the casting noise in client code
@SuppressWarnings("unchecked")
public static <T extends View> T get(View view, int id) {
SparseArray<View> viewHolder = (SparseArray<View>) view.getTag();
if (viewHolder == null) {
viewHolder = new SparseArray<View>();
view.setTag(viewHolder);
}
View childView = viewHolder.get(id);
if (childView == null) {
childView = view.findViewById(id);
viewHolder.put(id, childView);
}
return (T) childView;
}
}


好了,客户端的源码贴完了,接下来服务器端的源码就比较简单了

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

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: