转自u012711549:http://m.blog.youkuaiyun.com/article/details?id=51232855
以下为转载内容:
对于初学者,Android的网络通信是大家都喜欢但是又会感觉很难处理的模块。特别数据传输方面,初学者很可能犯一个很容易犯的错误,就是客户端通过字节数组或者对象与服务器端交换数据,但最后会发现它们都很不可行(用字节流时在与服务器端交互数据的时候很难操作控制,很难让服务器端知道什么时候应该开始下一步的处理;用对象交换数据的时候,交换要求是客户端和服务器端必须有类名、包名、内容完全相同的类,这样很难做到跨语言的通讯)。因此我采用了字符流的形式传送数据并对网络的访问做了一系列的封装,希望能够帮助到你。废话就不多说了,开始切入正题吧。
客户端与服务器端交互主要的思想为:客户端把数据转化为JSON格式的字符串再发给服务器端(字符串主要包含两个部分:操作码,数据。转化方式为:把数据传入到模板类的对象中,通过FastJson把对象转化为字符串)。服务器端接收到字符串之后再把字符串转化为模板类的对象(转化方式为:先通过FastJson把字符串转化为JSON对象格式的数据,再把JSON对象转化为模板类的对象),服务器端根据操作码来做不同的处理,处理之后把数据封装到模板类的对象中,FastJson再把模板类的对象转化为字符串传给客户端,客户端接收到字符串数据之后再把字符串数据转化为模板类的对象(转化方式同上),客户端再通过模板类做相应的处理。
客户端发送给服务器端的数据主要格式为:
{
code:1, data:[ {},{}
]
}
- 1
- 2
- 3
- 4
- 5
- 6
服务器端发送给客户端的数据主要格式为:
{
ok:true, data:{}
}
- 1
- 2
- 3
- 4
或者
{
ok:true, data:[ {},{}
]
}
- 1
- 2
- 3
- 4
- 5
- 6
看起来是不是很简单呢,那么开始代码讲解了吧。
安卓端:
主要使用到了如下几个类:
数据请求模板类RequestMessage(主要用来封装发给服务器端的数据) :
package com.szhushou.ssp.connection;
import java.util.Map;
public class RequestMessage {
private Integer code;//操作码
private Map<String, String> data;//传送给服务器端的数据
public void setCode(Integer code) {
this.code = code;
}
public void setData(Map<String, String> data) {
this.data = data;
}
public Integer getCode() {
return code;
}
public Map<String, String> getData() {
return data;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
网络传输核心类SocketConnection(主要用来封装最基本的数据传输类):
package com.szhushou.ssp.connection;
import android.util.Log;
import com.alibaba.fastjson.JSON;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
public class SocketConnection {
private final static String TAG = "SocketConnection";
private final static String END = "#end#";//用来结束发送的字符串
private Socket client = null;
private BufferedReader ois = null;
private PrintStream oos = null;
public SocketConnection(String ip, int host) throws IOException {
client = new Socket(ip, host);
oos = new PrintStream(client.getOutputStream());
ois = new BufferedReader(new InputStreamReader(client.getInputStream()));
}
public String requestData(RequestMessage messageOut) throws IOException {
String result;
String json = JSON.toJSONString(messageOut);
sendString(oos, json);
result = readString(ois);
Log.i(TAG, result);
oos.close();
ois.close();
if (!client.isClosed()) {
client.close();
}
return result;
}
/**
*用来读取输入流的内容
*/
private String readString(BufferedReader ois) throws IOException {
String result;
String bufferText;
StringBuffer resultBuffer = new StringBuffer();
while (!(bufferText = ois.readLine()).equals(END)) {
resultBuffer.append(bufferText);
}
result = resultBuffer.toString();
return result;
}
/**
*用来写入数据到输出流
*/
private void sendString(PrintStream out, String text) {
out.println(text);
out.println(END);
out.flush();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
业务逻辑的数据传输类Connection(主要用来对SocketConnection 进行进一步的封装处理,用来实现Android的网络线程异步处理,可以通过继承Connection类实现getData方法来做其他数据,如String格式的数据处理) :
package com.szhushou.ssp.connection;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import com.alibaba.fastjson.JSONObject;
import java.io.IOException;
/**
* Created by xiaofeng on 2016-04-19.
*/
public abstract class Connection {
private final static String TAG="Connection";
private String ip;
private int host;
public Connection(String ip,int host){
this.ip=ip;
this.host=host;
}
/**
* 发送数据给服务器端
* @param requestData 请求的数据
* @param resultClass 接收的数据类的类型
* @param successListener 访问数据成功的回调函数
* @param failListener 访问数据失败的回调函数,失败主要包含两种失败,网络通信失败和服务器返回的ok值为false的失败,如果是网络通信失败onFile会返回IOException,如果是ok为false onFile会返回DataNullException
* @param <T> 模板类
*/
public <T> void sendRequest(final RequestMessage requestData,Class<T> resultClass,SuccessListener<T> successListener,FailListener failListener){
final MyHandler<T> handler=new MyHandler<T>(successListener,failListener,resultClass);
new Thread(){
@Override
public void run(){
boolean ok;
String result;
try {
result = new SocketConnection(ip,host).requestData(requestData);
ok=true;
} catch (IOException e) {
e.printStackTrace();
result="";
ok=false;
}
Bundle bundle=new Bundle();
bundle.putBoolean("ok", ok);
bundle.putString("data", result);
Message message=new Message();
message.setData(bundle);
handler.sendMessage(message);
}
}.start();
}
/**
*用来处理异步通讯
*/
private class MyHandler<T> extends Handler {
private SuccessListener<T> mSuccessListener;
private FailListener mFailListener;
private Class<T> mClass;
public MyHandler(SuccessListener<T> successListener,FailListener failListener, Class<T> clazz) {
super();
this.mSuccessListener = successListener;
this.mFailListener=failListener;
this.mClass = clazz;
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle data = msg.getData();
String result = data.getString("data");
boolean ok = data.getBoolean("ok");
Log.i(TAG,result);
if(ok==true) {
JSONObject jsonObject=JSONObject.parseObject(result);
boolean isOk=jsonObject.getBoolean("ok");
if(isOk==true) {
T resultData = getData(jsonObject,mClass);
mSuccessListener.onResponse(resultData);
}else {
String remindText=jsonObject.getString("data");
if(remindText==null) {
mFailListener.onFile(new DataNullException());
}else {
mFailListener.onFile(new DataNullException(remindText));
}
}
}else {
mFailListener.onFile(new IOException());
}
}
}
/**
* ok值为false抛出的提示异常,如果服务器端未传递值给data,则调用getMessage返回的值是null,如果服务器端有传递值给data,则调用getMessage返回的值为data对应的值
*/
public class DataNullException extends Exception{
private String message;
public DataNullException(){
super();
}
public DataNullException(String detailMessage){
super(detailMessage);
message=detailMessage;
}
@Override
public String getMessage() {
return message;
}
}
/**
* 该方法用来给继承实现,主要是为了去处理结果数据为数组或者为单一对象问题
* @param jsonObject 封装有数据的Json
* @param mClass 返回结果的类型
* @param <T> 结果的类型
* @return 转化后的结果
*/
protected abstract <T> T getData(JSONObject jsonObject,Class<T> mClass);
public interface SuccessListener<T>{
public void onResponse(T t);
}
public interface FailListener{
public void onFile(Exception e);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
Conection的扩展类,主要用来处理数据返回为单一对象的操作类ObjectConnection
package com.szhushou.ssp.connection;
import com.alibaba.fastjson.JSONObject;
/**
* Created by xiaofeng on 2016-04-19.
*/
public class ObjectConnection extends Connection {
public ObjectConnection(String ip, int host) {
super(ip, host);
}
@Override
protected <T> T getData(JSONObject jsonObject,Class<T> mClass){
return JSONObject.toJavaObject(jsonObject.getJSONObject("data"), mClass);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
Conection的扩展类,主要用来处理数据返回为对象数组的操作类ArrayConnection:
package com.szhushou.ssp.connection;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
/**
* Created by xiaofeng on 2016-04-19.
*/
public class ArrayConnection extends Connection {
public ArrayConnection(String ip, int host) {
super(ip, host);
}
@Override
protected <T> T getData(JSONObject jsonObject, Class<T> mClass) {
return JSONArray.toJavaObject(jsonObject.getJSONArray("data"), mClass);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
核心类已经写完了,如果不能理解也不要紧,只需要会调用就可以了,以下是用于安卓端调用的核心方法。
try {
Map<String, String> map = new HashMap<String, String>();
map.put("name", "client");
map.put("metter","hello world!");
RequestMessage requestMessage = new RequestMessage();
requestMessage.setCode(1);
requestMessage.setData(map);
new ObjectConnection("192.168.191.1",6000).sendRequest(requestMessage, ResponseContent.class, new Connection.SuccessListener<ResponseContent>() {
@Override
public void onResponse(ResponseContent responseContent) {
//TODO 用来处理接收到的数据,数据都封装到resposeContent中了
}
}, new Connection.FailListener() {
@Override
public void onFile(Exception e) {
Toasts.showShort("出现异常,识别失败");//TODO Toasts是为了简写Toast而写的工具类,你可以直接用Toast的语法修改回来就可以了。
}
});
} catch (IOException e) {
Toasts.showShort(MainViewActivity.this,"查询失败,文件读写异常");
}catch (Exception e) {
Toasts.showShort(MainViewActivity.this,"查询失败,其他异常");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
服务器发送给客户端的数据的数据封装类ResponseContent(具体业务的一部分,可以根据实际需求修改):
package com.szhushou.ssp.model;
public class ResponseContent{
private String name;
private String metter;
public void setName(String name) {
this.name = name;
}
public void setMetter(String metter) {
this.metter = metter;
}
public String getName() {
return name;
}
public String getMetter() {
return metter;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
客户端的代码就介绍完了,接下来就是服务器端的了
服务器端:
服务器端程序入口类ServerMain(主要用来接收客户端的连接信息,把信息传递给线程处理):
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import com.szhushou.ssps.util.SystemMethod;
public class ServerMain
{
private static final String TAG = "ServerMain";
public static void main(String args[])
{
ServerSocket server;
try {
server = new ServerSocket(FinalValue.host);
Socket client;
while(true)
{
client=server.accept();
new SportThread(client).start();
}
} catch (IOException e) {
System.out.println(TAG+" main "+e.getMessage());
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
服务器端事件处理线程SportThread(主要用来处理或者分发处理业务逻辑,这是修改的重点):
package com.szhushou.ssps;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.szhushou.ssps.factory.FindImage;
import com.szhushou.ssps.factory.Login;
import com.szhushou.ssps.factory.MyFactory;
import com.szhushou.ssps.model.client.RequestMessage;
import com.szhushou.ssps.model.server.ResultMessage;
import com.szhushou.ssps.util.BeanList;
import com.szhushou.ssps.util.SpringFactory;
import com.szhushou.ssps.util.SystemMethod;
public class SportThread extends Thread {
private static final String TAG = "PublicMethod";
private final static String END = "#end#";// 用来结束发送的字符串
Socket client;
public SportThread(Socket client) {
this.client = client;//
}
public void run() {
try {
BufferedReader ois = new BufferedReader(new InputStreamReader(
client.getInputStream()));
PrintStream oos = new PrintStream(client.getOutputStream());
String requestData = readString(ois);
RequestMessage messageIn = JSON.parseObject(requestData,
RequestMessage.class);
ResultMessage messageOut = EventDispose(messageIn);
String resultData = JSONObject.toJSONString(messageOut);
sendString(oos, resultData);
ois.close();
oos.close();
if (!client.isClosed()) {
client.close();
}
} catch (IOException e) {
System.out.println(TAG+" run "+e.getMessage());
}
}
private String readString(BufferedReader ois) throws IOException {
String result;
String bufferText;
StringBuffer resultBuffer = new StringBuffer();
while (!(bufferText = ois.readLine()).equals(END)) {
resultBuffer.append(bufferText);
}
result = resultBuffer.toString();
return result;
}
private void sendString(PrintStream out, String text) {
out.println(text);
out.println(END);
out.flush();
}
public ResultMessage EventDispose(RequestMessage messageIn)
throws IOException {
ResultMessage messageOut = new ResultMessage();
int type = messageIn.getCode();
MyFactory factory = null;
try {
switch (type) {
case 1:
Map<String, String> map=messageIn.getData();
String name=map.get("name");
String metter=map.get("metter");
//TODO处理消息...
ResponseMetter responseMetter=new ResponseMetter();
responseMetter.setMetter("already get message");
responseMetter.setName("server");
messageOut=new ResultMessage(false,responseMetter);
break;
default:
break;
}
} catch (Exception e) {
System.out.println(TAG+" EventDispose "+ e.getMessage());
messageOut=new ResultMessage(false,null);
}
return messageOut;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
服务器端的接收消息模板类RequestMessage(主要是用来封装接收的信息的,慎改):
package com.szhushou.ssps.model.client;
import java.util.Map;
public class RequestMessage
{
private Integer code;
private Map<String, String> data;
public void setCode(Integer code) {
this.code = code;
}
public void setData(Map<String, String> data) {
this.data = data;
}
public Integer getCode() {
return code;
}
public Map<String, String> getData() {
return data;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
服务器端的返回结果模板类ResultMessage(主要用来封装发送给客户端的信息的,慎改):
package com.szhushou.ssps.model.server;
public class ResultMessage {
private boolean ok;
private Object data;
public ResultMessage(){
}
public ResultMessage(boolean ok,Object data){
this.ok=ok;
this.data=data;
}
public void setOk(boolean ok) {
this.ok = ok;
}
public void setData(Object data) {
this.data = data;
}
public boolean isOk() {
return ok;
}
public Object getData() {
return data;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
服务器端的消息封装类ResponseMetter(该类是用来封装具体信息的,内容和客户端的ResponseContent对应,可以根据业务修改和新建):
package com.szhushou.ssps.model.server;
public class ResponseMetter{
private String name;
private String metter;
public void setName(String name) {
this.name = name;
}
public void setMetter(String metter) {
this.metter = metter;
}
public String getName() {
return name;
}
public String getMetter() {
return metter;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
提示:
本次代码的JSON部分主要使用带了阿里的开源代码FastJson,下载地址为:https://github.com/alibaba/fastjson/releases
总结:
经历了一上午,终于把博客写完了,如果有什么地方没考虑到部分,还望多多指教。后续有时间再继续跟进。