本篇文章是我以前写的一篇文章的改版,上一篇文章已删除,因为以前的博客有的朋友说运行不起来,我现在想起来所以重新修改了以下代码,因为我这测试机就两个,只能测试一个绘制者和一个观看者。
下面上代码,首先是我们的Android客户端-------------------
Android实现原理就是自定义View,然后继承的是SurfaceView,不继承View的原因就是SurfaceView这个视图里内嵌了一个专门用于绘制的Surface。
先看一下我们自定义的DrawGameView,也就是继承自SurfaceView的一个View。
public class DrawGameView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder holder;
private SurfaceThread thread;
WindowManager wm = (WindowManager) getContext()
.getSystemService(Context.WINDOW_SERVICE);
int screenW = wm.getDefaultDisplay().getWidth();
int screenH = wm.getDefaultDisplay().getHeight();
// private Canvas canvas;
public SurfaceThread getThread() {
return thread;
}
public DrawGameView(Context context) {
super(context);
init();
}
public DrawGameView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public void init() {
holder = getHolder();
holder.addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
thread = new SurfaceThread();
thread.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
public class SurfaceThread extends Thread {
private Path path;
private Paint paint;
private ArrayList<DrawStep> steps = new ArrayList<DrawStep>();
private ArrayList<Path> paths = new ArrayList<Path>();
public SurfaceThread() {
path = new Path();
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.BLUE);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
}
@Override
public void run() {
super.run();
while (true) {
draw();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void addStep(DrawStep step) {
steps.add(step);
}
public void draw() {
Canvas canvas = null;
try {
canvas = holder.lockCanvas();//锁整个画布
if (canvas != null) {
while (steps.size() > 0) {
DrawStep step = steps.remove(0);
if (step.getType() == DrawStep.MoveTo) {
path.moveTo(screenW * ((float) step.getxP() / 10000), screenH * ((float) step.getyP() / 10000));
} else if (step.getType() == DrawStep.LineTo) {
path.lineTo(screenW * ((float) step.getxP() / 10000), screenH * ((float) step.getyP() / 10000));
} else if (step.getType() == DrawStep.UP) {
Path path1 = new Path(path);
paths.add(path1);
}
}
for (int i = 0; i < paths.size(); i++) {
canvas.drawPath(paths.get(i), paint);
}
canvas.drawPath(path, paint);
holder.unlockCanvasAndPost(canvas);
}
} catch (Exception e) {
}
}
}
}
我先把所有代码贴上吧,没什么东西,如果有问题可以给我发私信。
MainActivity代码
public class MainActivity extends Activity {
private static DrawGameView drawGameView;
DisplayMetrics dm = new DisplayMetrics();
int screenW;
int screenH;
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
NetWorkMessage.get_Instance().setActivity(this);
drawGameView = new DrawGameView(this);
setContentView(drawGameView);
getWindowManager().getDefaultDisplay().getMetrics(dm);
screenW = dm.widthPixels;
screenH = dm.heightPixels;
drawGameView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (NetWorkMessage.get_Instance().isDrawer()) {
// if (true) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
addStep(DrawStep.MoveTo, (int) (event.getX() / screenW * 10000), (int) (event.getY() / screenH * 10000));
break;
case MotionEvent.ACTION_MOVE:
addStep(DrawStep.LineTo, (int) (event.getX() / screenW * 10000), (int) (event.getY() / screenH * 10000));
break;
case MotionEvent.ACTION_UP:
addStep(DrawStep.UP, 0, 0);
break;
}
return true;
} else {
return false;
}
}
});
}
public void addStep(byte type, int xp, int yp) {
DrawStep step = new DrawStep();
step.setType(type);
step.setxP(xp);
step.setyP(yp);
NetWorkMessage.get_Instance().sendDrawMsgToServer(step);
addOneStep(step);
}
public void addOneStep(DrawStep step) {
drawGameView.getThread().addStep(step);
}
// public static void drawStep(DrawStep drawStep) {
// drawGameView.postInvalidate();
drawView.forceLayout();
// }
}
GameApplication在这里做了Socket的初始化
public class GameApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
NetWorkMessage.get_Instance().createNetWork();
// NetWorkMessage.get_instaance().receiveLoginNetWork();
NetWorkMessage.get_Instance().receiveDrawNetWork();
}
}
Command定义的服务器与客户端交互的命令
public class Command {
public static final byte LOGIN = 1;
public static final byte DRAW = 2;
public static final byte LOGIN_OUT = 3;//登出
}
NetWorkMessage主要是处理Socket连接、接收和发送数据的
public class NetWorkMessage {
private final String TAG = "NetWorkMessage";
private Socket socket = new Socket();
private static NetWorkMessage _instance = new NetWorkMessage();
public boolean isDraw;
private MainActivity activity;
public MainActivity getActivity() {
return activity;
}
public void setActivity(MainActivity activity) {
this.activity = activity;
}
public static NetWorkMessage get_Instance() {
return _instance;
}
public void sendDrawMsgToServer(DrawStep drawStep) {
try {
//发送内容
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
int len = 10;
ByteArray data = new ByteArray();
data.writeInt(len);
data.writeByte(Command.DRAW);
data.writeByte(drawStep.getType());
data.writeInt(drawStep.getxP());
data.writeInt(drawStep.getyP());
outputStream.write(data.toByteArray());
outputStream.flush();
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG, "没有发送成功======客户端----断开连接");
}
}
public void createNetWork() {
new Thread(createNetwork).start();
}
public void receiveDrawNetWork() {
new Thread(receiveDrawNetwork).start();
}
private Runnable createNetwork = new Runnable() {
@Override
public void run() {
try {
// socket = new Socket("192.168.0.102", 8888);
socket = new Socket("192.168.1.105", 8888);
requestLogin();
} catch (IOException e) {
e.printStackTrace();
}
}
};
/**
* 请求登录
*/
private void requestLogin()
{
try{
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
String userKey = (String) SharedPreferencesUtil.getData(getActivity(), Configs.LOCAL_USER_KEY, "");
int len = 5 + userKey.length();
ByteArray data = new ByteArray();
data.writeInt(len);
data.writeByte(Command.LOGIN);
data.writeByteArray(userKey.getBytes());
outputStream.write(data.toByteArray());
outputStream.flush();
}catch (Exception e)
{
}
}
private Runnable receiveDrawNetwork = new Runnable() {
@Override
public void run() {
while (true) {
receiveDraw();
}
}
};
private void receiveDraw() {
//接收服务器返回信息
try {
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
if (inputStream.available() != 0) {
int len = inputStream.readInt();
byte[] buffer = new byte[len];
inputStream.read(buffer, 0, len);
ByteArray data = new ByteArray(buffer);
byte cmd = data.readByte();
if (cmd == Command.LOGIN) {
Log.d(TAG, "-----------BEGIN-----------------");
byte[] userKeyByteArr = data.readByteArray(5, 36);
Log.d(TAG, "-----------EDN-----------------");
String userKey = new String(userKeyByteArr);
if (userKey != null && !"".equals(userKey))
{
SharedPreferencesUtil.saveData(getActivity(), Configs.LOCAL_USER_KEY, userKey);
}
Log.d(TAG, "userKey=============" + userKey);
//12e0962f-3789-48a5-9b9e-74a256544949
int tag = data.readInt();
Log.d(TAG, "tag=============" + tag);
if (tag == 1) {
setDrawer(true);
} else {
setDrawer(false);
}
} else if (cmd == Command.DRAW) {
byte type = data.readByte();
int x = data.readInt();
int y = data.readInt();
DrawStep drawStep = new DrawStep();
drawStep.setxP(x);
drawStep.setyP(y);
drawStep.setType(type);
activity.addOneStep(drawStep);
}
// MainActivity.drawStep(msg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public boolean isDrawer() {
return isDraw;
}
public void setDrawer(boolean draw) {
isDraw = draw;
}
}
DrawSept,绘制的时候前后台交互传输的数据格式
public class DrawStep {
public static final byte MoveTo = 1;
public static final byte LineTo = 2;
public static final byte UP = 3;
private byte type;
private int xP;
private int yP;
public byte getType() {
return type;
}
public void setType(byte type) {
this.type = type;
}
public int getxP() {
return xP;
}
public void setxP(int xP) {
this.xP = xP;
}
public int getyP() {
return yP;
}
public void setyP(int yP) {
this.yP = yP;
}
}
SharePreferencesUtil 本地存储工具类,用来存储服务器返回的userKey
public class SharedPreferencesUtil {
//存储的sharedpreferences文件名
private static final String FILE_NAME = "save_file_name";
/**
* 保存数据到文件
*
* @param context
* @param key
* @param data
*/
public static void saveData(Context context, String key, Object data){
String type = data.getClass().getSimpleName();
SharedPreferences sharedPreferences = context
.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
if ("Integer".equals(type)){
editor.putInt(key, (Integer)data);
}else if ("Boolean".equals(type)){
editor.putBoolean(key, (Boolean)data);
}else if ("String".equals(type)){
editor.putString(key, (String)data);
}else if ("Float".equals(type)){
editor.putFloat(key, (Float)data);
}else if ("Long".equals(type)){
editor.putLong(key, (Long)data);
}
editor.commit();
}
/**
* 清除本地保存的数据
*
* @param context
* @param key
*/
public static void removeData(Context context, String key)
{
SharedPreferences sharedPreferences = context
.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.remove(key);
editor.commit();
}
/**
* 从文件中读取数据
* @param context
* @param key
* @param defValue
* @return
*/
public static Object getData(Context context, String key, Object defValue){
String type = defValue.getClass().getSimpleName();
SharedPreferences sharedPreferences = context.getSharedPreferences (FILE_NAME, Context.MODE_PRIVATE);
//defValue为为默认值,如果当前获取不到数据就返回它
if ("Integer".equals(type)){
return sharedPreferences.getInt(key, (Integer)defValue);
}else if ("Boolean".equals(type)){
return sharedPreferences.getBoolean(key, (Boolean)defValue);
}else if ("String".equals(type)){
return sharedPreferences.getString(key, (String)defValue);
}else if ("Float".equals(type)){
return sharedPreferences.getFloat(key, (Float)defValue);
}else if ("Long".equals(type)){
return sharedPreferences.getLong(key, (Long)defValue);
}
return null;
}
}
ByteArray
public class ByteArray {
/**
* DEFAULT_SIZE
*/
private static final byte DEFAULT_SIZE = 16;
/**
* BOOLEAN_SIZE
*/
static final public byte BOOLEAN_SIZE = 1;
/**
* BYTE_SIZE
*/
static final public byte BYTE_SIZE = 1;
/**
* CHAR_SIZE
*/
static final public byte CHAR_SIZE = 2;
/**
* SHORT_SIZE
*/
static final public byte SHORT_SIZE = 2;
/**
* INT_SIZE
*/
static final public byte INT_SIZE = 4;
/**
* LONG_SIZE
*/
static final public byte LONG_SIZE = 8;
/**
* 当前位置
*/
private int currentPos = 0;
/**
* byte数组数据
*/
private byte[] data;
/**
* 默认大小构造
*/
public ByteArray() {
this(DEFAULT_SIZE);
}
/**
* 指定大小构造
*
* @param size 指定的大小
*/
public ByteArray(int size) {
data = new byte[size];
currentPos = 0;
}
/**
* 指定数据构造
*
* @param src 指定的数据源
*/
public ByteArray(byte[] src) {
data = src;
currentPos = 0;
}
/**
* writeBoolean
*
* @param val
*/
public void writeBoolean(boolean val) {
ensureCapacity(BOOLEAN_SIZE);
data[currentPos++] = (byte) (val ? 1 : 0);
}
/**
* writeByte
*
* @param val
*/
public void writeByte(byte val) {
ensureCapacity(BYTE_SIZE);
data[currentPos++] = val;
}
/**
* writeByte
*
* @param val
*/
public void writeByte(int val) {
writeByte((byte) val);
}
/**
* writeChar
*
* @param c
*/
public void writeChar(char c) {
ensureCapacity(CHAR_SIZE);
data[currentPos + 1] = (byte) (c >>> 0);
data[currentPos + 0] = (byte) (c >>> 8);
currentPos += 2;
}
/**
* writeShort
*
* @param val
*/
public void writeShort(short val) {
ensureCapacity(SHORT_SIZE);
data[currentPos + 1] = (byte) (val >>> 0);
data[currentPos + 0] = (byte) (val >>> 8);
currentPos += 2;
}
/**
* writeShort
*
* @param val
*/
public void writeShort(int val) {
writeShort((short) val);
}
/**
* writeInt
*
* @param val
*/
public void writeInt(int val) {
ensureCapacity(INT_SIZE);
data[currentPos + 3] = (byte) (val >>> 0);
data[currentPos + 2] = (byte) (val >>> 8);
data[currentPos + 1] = (byte) (val >>> 16);
data[currentPos + 0] = (byte) (val >>> 24);
currentPos += INT_SIZE;
}
/**
* writeLong
*
* @param val
*/
public void writeLong(long val) {
ensureCapacity(LONG_SIZE);
data[currentPos + 7] = (byte) (val >>> 0);
data[currentPos + 6] = (byte) (val >>> 8);
data[currentPos + 5] = (byte) (val >>> 16);
data[currentPos + 4] = (byte) (val >>> 24);
data[currentPos + 3] = (byte) (val >>> 32);
data[currentPos + 2] = (byte) (val >>> 40);
data[currentPos + 1] = (byte) (val >>> 48);
data[currentPos + 0] = (byte) (val >>> 56);
currentPos += LONG_SIZE;
}
/**
* writeByteArray
*
* @param src
*/
public void writeByteArray(byte[] src) {
if (src == null) {
return;
}
ensureCapacity(src.length);
System.arraycopy(src, 0, data, currentPos, src.length);
currentPos += src.length;
}
/**
* writeUTF
*
* @param str
*/
public void writeUTF(String str) {
writeByteArray(getByteArrFromUTF(str));
}
/**
* readBoolean
*
* @return
*/
public boolean readBoolean() {
// if(checkCapacity(BOOLEAN_SIZE)){
// return false;
// }
return data[currentPos++] != 0;
}
/**
* readByte
*
* @return
*/
public byte readByte() {
// if(checkCapacity(BYTE_SIZE)){
// return -1;
// }
return data[currentPos++];
}
/**
* readChar
*
* @return
*/
public char readChar() {
// if(checkCapacity(CHAR_SIZE)){
// return '1';
// }
char c = (char) (((data[currentPos + 1] & 0xFF) << 0) +
((data[currentPos + 0] & 0xFF) << 8));
currentPos += CHAR_SIZE;
return c;
}
/**
* readShort
*
* @return
*/
public short readShort() {
short s = (short) (((data[currentPos + 1] & 0xFF) << 0) +
((data[currentPos + 0] & 0xFF) << 8));
currentPos += SHORT_SIZE;
return s;
}
/**
* readInt
*
* @return
*/
public int readInt() {
int i = ((data[currentPos + 3] & 0xFF) << 0) +
((data[currentPos + 2] & 0xFF) << 8) +
((data[currentPos + 1] & 0xFF) << 16) +
((data[currentPos + 0] & 0xFF) << 24);
currentPos += INT_SIZE;
return i;
}
/**
* readLong
*
* @return
*/
public long readLong() {
long l = ((data[currentPos + 7] & 0xFFL) << 0) +
((data[currentPos + 6] & 0xFFL) << 8) +
((data[currentPos + 5] & 0xFFL) << 16) +
((data[currentPos + 4] & 0xFFL) << 24) +
((data[currentPos + 3] & 0xFFL) << 32) +
((data[currentPos + 2] & 0xFFL) << 40) +
((data[currentPos + 1] & 0xFFL) << 48) +
((data[currentPos + 0] & 0xFFL) << 56);
currentPos += LONG_SIZE;
return l;
}
/**
* readByteArray
*
* @param length
* @return
*/
public byte[] readByteArray(int length) {
if (length == -1 || currentPos + length > data.length) {
length = data.length - currentPos;
}
byte[] temp = new byte[length];
System.arraycopy(data, currentPos, temp, 0, length);
currentPos += length;
return temp;
}
/**
* readByteArray
*
* @param off
* @param length
* @return
*/
public byte[] readByteArray(int off, int length) {
if (length == -1 || off + length > data.length) {
length = data.length - off;
}
byte[] temp = new byte[length];
System.arraycopy(data, off, temp, 0, length);
return temp;
}
/**
* readUTF
*
* @return
*/
public String readUTF() {
int utflen = readUnsignedShort();
if (utflen == -1) {
System.err.println("Error!! ByteArray: readUTF()");
return "ERROR";
}
byte[] bytearr = null;
char[] chararr = null;
bytearr = readByteArray(utflen);
chararr = new char[utflen];
int c, char2, char3;
int count = 0;
int chararr_count = 0;
while (count < utflen) {
c = (int) bytearr[count] & 0xff;
if (c > 127) {
break;
}
count++;
chararr[chararr_count++] = (char) c;
}
while (count < utflen) {
c = (int) bytearr[count] & 0xff;
switch (c >> 4) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7: /* 0xxxxxxx*/
count++;
chararr[chararr_count++] = (char) c;
break;
case 12:
case 13: /* 110x xxxx 10xx xxxx*/
count += 2;
char2 = (int) bytearr[count - 1];
chararr[chararr_count++] = (char) (((c & 0x1F) << 6) |
(char2 & 0x3F));
break;
case 14: /* 1110 xxxx 10xx xxxx 10xx xxxx */
count += 3;
char2 = (int) bytearr[count - 2];
char3 = (int) bytearr[count - 1];
chararr[chararr_count++] = (char) (((c & 0x0F) << 12) |
((char2 & 0x3F) << 6) |
((char3 & 0x3F) << 0));
break;
default:
break;
}
}
return new String(chararr, 0, chararr_count);
}
/**
* 检测data数组是否足够长
*
* @param length int
*/
private void ensureCapacity(int length) {
if (currentPos + length >= data.length) {
byte[] tmp = new byte[data.length + 2 * length];
System.arraycopy(data, 0, tmp, 0, data.length);
data = tmp;
}
}
/**
* getByteArrFromUTF
*
* @param str
* @return
*/
public static byte[] getByteArrFromUTF(String str) {
int strlen = str.length();
int utflen = 0;
int c, count = 0;
/* use charAt instead of copying String to char array */
for (int i = 0; i < strlen; i++) {
c = str.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
utflen++;
} else if (c > 0x07FF) {
utflen += 3;
} else {
utflen += 2;
}
}
byte[] bytearr = new byte[utflen + 2];
bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
int i = 0;
for (i = 0; i < strlen; i++) {
c = str.charAt(i);
if (!((c >= 0x0001) && (c <= 0x007F))) {
break;
}
bytearr[count++] = (byte) c;
}
for (; i < strlen; i++) {
c = str.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
bytearr[count++] = (byte) c;
} else if (c > 0x07FF) {
bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));
bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
} else {
bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
}
}
return bytearr;
}
/**
* readUnsignedByte
*
* @return
*/
private int readUnsignedByte() {
return data[currentPos++] & 0x00FF;
}
/**
* readUnsignedShort
*
* @return
*/
private int readUnsignedShort() {
int ch1 = readUnsignedByte();
int ch2 = readUnsignedByte();
if ((ch1 | ch2) < 0) {
return -1;
}
return (ch1 << 8) + (ch2 << 0);
}
/**
* toByteArray
*
* @return
*/
public byte[] toByteArray() {
if (currentPos < data.length) {
return readByteArray(0, currentPos);
}
return data;
}
/**
* resetPosition
*/
public void resetPosition() {
currentPos = 0;
}
/**
* close
*/
public void close() {
data = null;
}
/**
* bytesToInts
*
* @param bytes
* @return
*/
public static int[] bytesToInts(byte[] bytes) {
if (bytes == null || bytes.length < 4) {
return null;
}
int[] ints = new int[bytes.length >> 2];
ByteArray ba = new ByteArray(bytes);
for (int i = 0, kk = ints.length; i < kk; i++) {
ints[i] = ba.readInt();
}
return ints;
}
/**
* intsToBytes
*
* @param ints
* @return
*/
public static byte[] intsToBytes(int[] ints) {
if (ints == null || ints.length <= 0) {
return null;
}
byte[] bytes = new byte[ints.length << 2];
ByteArray ba = new ByteArray(bytes);
for (int i = 0, kk = ints.length; i < kk; i++) {
ba.writeInt(ints[i]);
}
return ba.toByteArray();
}
/**
* getLength
*
* @return
*/
public int getLength() {
return data.length;
}
/**
* 得到字节数组
*
* @return byte[]
*/
public byte[] toArray() {
byte[] tmp = new byte[currentPos];
System.arraycopy(data, 0, tmp, 0, currentPos);
return tmp;
}
/**
* 追加byte数组
*
* @param data
*/
public void append(byte[] data) {
writeByteArray(data);
}
}
然后就是服务器源码---------
DrawServer
public class DrawServer
{
private static DrawServer _instance;
private static HashMap<Integer,SocketThread> users=new HashMap<Integer, SocketThread>();//用户key,线程
private int index=0;
public static void main(String[] args) {
DrawServer.getInstance().start();
}
public static DrawServer getInstance()
{
if (_instance == null)
{
synchronized (DrawServer.class)
{
if (_instance == null)
{
_instance = new DrawServer();
}
}
}
return _instance;
}
private void start() {
try {
@SuppressWarnings("resource")
ServerSocket server = new ServerSocket(8888);// 创建一个Socket服务器对象,进行监听8888的端口
System.out.println("------服务器启动------");
while (true) {
Socket client = server.accept();// 收到一个客户端连接
System.out.println("------服务器监听到一个客户端连接------");
addUser(new SocketThread(client)).start();// 开启一个线程与客户端进行数据传输
}
} catch (IOException e) {
e.printStackTrace();
}
}
public SocketThread addUser(SocketThread thread)
{
LoginHandler.getInstance().setOnClientLogin(new LoginHandler.IOnClientLoginListener() {
@Override
public void onLogin(String userKey) {
if (userKey == null || "".equals(userKey))
{
index++;
//发送第一次登陆成功消息
LoginHandler.getInstance().sendFirstLoginSuccessMsg(index,thread);
users.put(index, thread);//主键递增(保存发给客户端
}else{
if (UserManager.getInstance().userKeyIsExist(userKey))
{
//如果已存在
LoginHandler.getInstance().sendLoginSuccessMsg(index,thread);
}else {//不存在的话认为是第一次登录
index++;
//发送第一次登陆成功消息
LoginHandler.getInstance().sendFirstLoginSuccessMsg(index,thread);
users.put(index, thread);//主键递增(保存发给客户端
}
}
thread.setKey(index);
}
});
// LoginHandler.getInstance().setSocket(thread);
// DrawHandler.getInstance().setSocket(thread);
thread.setOnClientOut(new SocketThread.IOnClientOutListener() {
@Override
public void onClientOut() {
index--;
}
});
return thread;
}
public void removeUser(int key)
{
if(users.containsKey(key))
{
users.remove(key);
}
}
//全员广播
public void broadcastAllMsg(ByteArray data,int ignoreKey)
{
Iterator<Integer> iter=users.keySet().iterator();
while(iter.hasNext())
{
Integer key=iter.next();
if(key!=ignoreKey)
{
SocketThread thread=users.get(key);
if(thread!=null&&thread.isConnection()) thread.putMsg(data);
}
}
}
}
BaseHandler
//发送数据
public void sendMsg(ByteArray data,SocketThread thread)
{
thread.putMsg(data);;
}
//接收数据
public void recviveMsg(ByteArray data,SocketThread thread)
{
}
DrawHandler
public class DrawHandler extends BaseHandler
{
private static DrawHandler _instance=new DrawHandler();
public static DrawHandler getInstance()
{
return _instance;
}
//接收数据
@Override
public void recviveMsg(ByteArray data,SocketThread thread)
{
//接收到消息转发
int len=10;
ByteArray result=new ByteArray();
result.writeInt(len);
result.writeByte(Command.DRAW);
result.writeByte(data.readByte());//类型
result.writeInt(data.readInt());
result.writeInt(data.readInt());
DrawServer.getInstance().broadcastAllMsg(result, thread.getKey());
}
LoginHandler
public class LoginHandler extends BaseHandler {
private static LoginHandler _instance = new LoginHandler();
public static LoginHandler getInstance() {
return _instance;
}
//发送第一次登录成功数据
public void sendFirstLoginSuccessMsg(int key, SocketThread thread) {
ByteArray data = new ByteArray();
String userKey = UserManager.getInstance().createUserKey();
UserManager.getInstance().saveAUserKey(userKey);//储存一个UserKey并且把这个生成的UserKey发送到客户端
int len = 5 + userKey.length();
data.writeInt(len);
data.writeByte(Command.LOGIN);
data.writeInt(key);
data.writeByteArray(userKey.getBytes());
super.sendMsg(data, thread);
}
//发送登录成功数据
public void sendLoginSuccessMsg(int key, SocketThread thread) {
ByteArray data = new ByteArray();
int len = 5;
data.writeInt(len);
data.writeByte(Command.LOGIN);
data.writeInt(key);
super.sendMsg(data, thread);
}
//接收数据
public void recviveMsg(ByteArray data, SocketThread thread) {
try {
byte cmd = data.readByteArray(0, 1)[0];
String userKey = new String(data.readByteArray(1, 36));
switch (cmd) {
case Command.LOGIN:
doLogin(userKey);
break;
case Command.LOGIN_OUT://登出操作,需要把储存的用户主键清除
break;
}
} catch (Exception e) {
}
}
/**
* 做登录操作
*/
private void doLogin(String userKey) {
if (mIOnClientLoginListener != null) {
mIOnClientLoginListener.onLogin(userKey);
}
}
private IOnClientLoginListener mIOnClientLoginListener;
public void setOnClientLogin(IOnClientLoginListener onClientLogin) {
mIOnClientLoginListener = onClientLogin;
}
interface IOnClientLoginListener {
void onLogin(String userKey);
}
}
SocketThread
public class SocketThread extends Thread
{
private Socket msocket;
private DataOutputStream out = null;
private boolean isConnection = false;
private int key;// 客户端和服务器通信标示
private BaseHandler handler;
public BaseHandler getHandler() {
return handler;
}
public void setHandler(BaseHandler handler) {
this.handler = handler;
}
private ArrayList<ByteArray> msg = new ArrayList<ByteArray>();
@Override
public void run() {
isConnection = true;
while (isConnection) {
try {
// 读取
ByteArray result = readSocketData();
if (result != null) {
byte cmd = result.readByte();// 命令号
switch (cmd) {
case Command.LOGIN:
LoginHandler.getInstance().recviveMsg(result, this);
break;
case Command.DRAW:
DrawHandler.getInstance().recviveMsg(result, this);
break;
case Command.LOGIN_OUT:
LoginHandler.getInstance().recviveMsg(result, this);
break;
}
}
// --------------------------
// 发送
while (msg.size() > 0) {
sendMsg(msg.remove(0));
}
Thread.sleep(17);
} catch (Exception e) {
breakClient();
}
}
}
// 放入发送队列
public void putMsg(ByteArray data) {
msg.add(data);
}
// 向客户端推送消息
private void sendMsg(ByteArray msg) {
try {
out = new DataOutputStream(msocket.getOutputStream());
byte[] b = msg.toByteArray();
out.write(b);
out.flush();
} catch (IOException e) {
breakClient();
}
}
// 客户端断开,移除用户连接
private void breakClient() {
isConnection = false;
System.out.println("客户端--" + getKey() + "--断开");
DrawServer.getInstance().removeUser(getKey());
try {
out.close();
msocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// 读取一个数据包
private ByteArray readSocketData() {
ByteArray bytearr = null;
DataInputStream input;
try {
input = new DataInputStream(msocket.getInputStream());
if (input.available() > 0) {
int len = input.readInt();// 数据长度
byte[] bytes = new byte[len];
input.read(bytes, 0, len);
bytearr = new ByteArray(bytes);
}
} catch (Exception e) {
e.printStackTrace();
}
return bytearr;
}
public boolean isConnection() {
return isConnection;
}
public SocketThread(Socket socket) {
this.msocket = socket;
}
public int getKey() {
return key;
}
public void setKey(int key) {
this.key = key;
}
private IOnClientOutListener mOnClientOutListener;
public void setOnClientOut(IOnClientOutListener onClientOut)
{
mOnClientOutListener = onClientOut;
}
interface IOnClientOutListener{
void onClientOut();
}
}
UserManager
public class UserManager {
private static UserManager _instance;
private static ArrayList<String> userKeys;
private UserManager()
{
}
public static UserManager getInstance()
{
if (_instance == null)
{
synchronized (UserManager.class)
{
if (_instance == null)
{
_instance = new UserManager();
}
}
}
if (userKeys == null)
{
createUserKeyList();
}
return _instance;
}
private static void createUserKeyList()
{
synchronized (UserManager.class)
{
if (userKeys == null)
{
userKeys = new ArrayList<String>();
}
}
}
public ArrayList<String> getAllUserKey()
{
return userKeys;
}
/**
* 保存一个用户主键
* @param userKey
*/
public ArrayList<String> saveAUserKey(String userKey)
{
userKeys.add(userKey);
return userKeys;
}
/**
* 移除一个用户主键
* @param userKey
* @return
*/
public ArrayList<String> removeAUserKey(String userKey)
{
userKeys.remove(userKey);
return userKeys;
}
/**
* 生成一个用户主键
* @return
*/
public String createUserKey()
{
return UUID.randomUUID().toString();
}
/**
* 该userKey是否存在
* @param userKey
* @return
*/
public boolean userKeyIsExist(String userKey)
{
boolean isExist = false;
int leg = userKeys.size();
for (int i = 0; i < leg; i++) {
if (userKey.equals(userKeys.get(i)))
{
isExist = true;
}
}
return isExist;
}
}
记住运行Android项目的时候要把NetWorkMessage的Socket连接的IP改成你自己电脑,然后Java项目也需要先跑起来,否则的话Socket连接不上,没有指令返回来,手机端是做不了任何操作的!!
源码下载:https://download.csdn.net/download/zhaohui_android/10726142
如果有问题请留言!!!