Android学习13-----网络通信(2) 与Socket交换数据
对于网络开发而言,最常用的交互模式:WebService、Web Server、Socket程序,一些Socket程序的使用要比JSP/Servlet等程序更加安全,所以在许多的Android手机端都会利用Socket进行数据的交互。下面我们来完成一个简单的Echo程序
首先定义服务器端程序,MyServer.java
package com.iflytek.server;import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.PrintStream;import java.net.ServerSocket;import java.net.Socket;/** * @author xdwang ** @create 2012-11-16 下午9:46:04 ** @email:xdwangiflytek@gmail.com ** @description Socket 服务 **/public class MyServer {public static void main(String[] args) {try {ServerSocket server = new ServerSocket(8888);// 在8888端口上监听Socket client = server.accept();// 接受客户端请求PrintStream out = new PrintStream(client.getOutputStream());// 取得客户端输出流BufferedReader buf = new BufferedReader(new InputStreamReader(client.getInputStream()));// 字符缓冲区读取StringBuffer info = new StringBuffer();// 接受客户端的信息info.append("Android:");// 回应数据info.append(buf.readLine());// 接受数据out.print(info);// 发送信息out.close();buf.close();client.close();server.close();} catch (Exception e) {}}}Android客户端,Socket01_EchoActivity.java
package com.iflytek.demo;import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.PrintStream;import java.net.Socket;import android.app.Activity;import android.os.AsyncTask;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;public class Socket01_EchoActivity extends Activity {private Button send = null;private TextView infoTxt = null;public Handler handler = new Handler() {@Overridepublic void handleMessage(android.os.Message msg) {super.handleMessage(msg);switch (msg.what) {case 1:infoTxt.setText(msg.obj.toString());break;default:break;}}};/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);this.send = (Button) super.findViewById(R.id.send);this.infoTxt = (TextView) super.findViewById(R.id.info);this.send.setOnClickListener(new SendOnClickListener());}private class SendOnClickListener implements OnClickListener {@Overridepublic void onClick(View v) {final AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {@Overrideprotected void onPostExecute(String result) {final String temp = result;Thread thread = new Thread(new Runnable() {@Overridepublic void run() {Message msg = new Message();msg.what = 1;msg.obj = temp;handler.sendMessage(msg);}});thread.start();}@Overrideprotected void onPreExecute() {super.onPreExecute();}@Overrideprotected String doInBackground(Void... arg0) {String result = "";try {Socket client = new Socket("IP", 8888);// 指定服务器PrintStream out = new PrintStream(client.getOutputStream());// 打印流输出BufferedReader buf = new BufferedReader(new InputStreamReader(client.getInputStream()));// 缓冲区读取out.println("王旭东"); // 向服务器端发送数据result = buf.readLine();out.close();buf.close();client.close();} catch (Exception e) {e.printStackTrace();}return result;}};task.execute();}}}AndroidManifest.xml同样需要访问网络的权限
<uses-permission android:name="android.permission.INTERNET" />其实在Android之中所编写的客户端代码与在java中所编写的Socket程序的客户端代码的功能是完全一样的,没有任何区别。
Ok,我们再来看看利用Socket进行上传操作,在完成上传的同时,附加多种数据如文件标题、大小等。
其实现方式:
1、我们可以直接将所有数据通过字节数组传送,如果采用这种方式,则需要传送两类数据,一种数据类型是自定义的头信息(如文件类型、大小等都通过头信息传递);另一种数据类型才是真正要上传的文件内容。但是这样做在服务器端的接收会比较麻烦,因为所有的数据都是按照字节流的方式传输的,所以必须在各种不同的数据间设置分隔符,而后取出数据时必须处理掉这些分隔符。
2、通过对象序列化的方法完成,使用一个专门的长传数据封装类,将所有的数据内容、文件内容(以字节数组保存)进行封装,而后利用对象序列化的方式,将该对象送到服务器端。使用这种方式处理较为容易,也很方便。
首先定义包装数据的序列化对象类,UploadFile.java
package com.iflytek.util;import java.io.Serializable;/** * @author xdwang ** @create 2012-11-16 下午10:39:01 ** @email:xdwangiflytek@gmail.com ** @description 数据的序列化对象类,进行序列化传输 **/@SuppressWarnings("serial")public class UploadFile implements Serializable {private String title;//信息标题private byte[] contentData;//文件内容private String mimeType;//文件类型private long contentLength;//文件长度private String ext;//扩展名public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public byte[] getContentData() {return contentData;}public void setContentData(byte[] contentData) {this.contentData = contentData;}public String getMimeType() {return mimeType;}public void setMimeType(String mimeType) {this.mimeType = mimeType;}public long getContentLength() {return contentLength;}public void setContentLength(long contentLength) {this.contentLength = contentLength;}public String getExt() {return ext;}public void setExt(String ext) {this.ext = ext;}}然后服务器端也要一个相同的类
服务器端服务类,MyServer02.java
package com.iflytek.server;import java.net.ServerSocket;public class MyServer02 {public static void main(String[] args) {try {String ss = "";System.out.println(ss);// 调用线程类启动服务ServerSocket server = new ServerSocket(8889); // 服务器端端口boolean flag = true; // 定义标记,可以一直死循环while (flag) { // 通过标记判断循环new Thread(new ServerThreadUtil(server.accept())).start(); // 启动线程}server.close(); // 关闭服务器} catch (Exception e) {}}}服务器端的多线程操作类,ServerThreadUtil.java
package com.iflytek.server;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.OutputStream;import java.io.PrintStream;import java.net.Socket;import java.util.UUID;import com.iflytek.util.UploadFile;/** * @author xdwang ** @create 2012-11-16 下午10:49:46 ** @email:xdwangiflytek@gmail.com ** @description 多线程操作类 **/public class ServerThreadUtil implements Runnable {private static final String DIRPATH = "D:" + File.separator + "xdwang"+ File.separator; // 保存文件夹private Socket client = null;//接受客户端private UploadFile uploadFile = null;//传递对象public ServerThreadUtil(Socket client) {//通过构造方法设置Socketthis.client = client;System.out.println("新的客户端连接...");}@Overridepublic void run() {try {PrintStream out = new PrintStream(this.client.getOutputStream());//取得客户端的输出流ObjectInputStream ois = new ObjectInputStream(client.getInputStream()); // 取得客户端的输入流,反序列化this.uploadFile = (UploadFile) ois.readObject(); // 读取对象System.out.println("文件标题:" + this.uploadFile.getTitle());System.out.println("文件类型:" + this.uploadFile.getMimeType());System.out.println("文件大小:" + this.uploadFile.getContentLength());out.print(this.saveFile());//返回标记} catch (Exception e) {e.printStackTrace();} finally {try {this.client.close();//关闭客户端连接} catch (IOException e) {e.printStackTrace();}}}/** * @descrption 进行文件保存 * @author xdwang * @create 2012-11-16下午10:52:18 * @return * @throws Exception */private boolean saveFile() throws Exception { File file = new File(DIRPATH + UUID.randomUUID() + "."+ this.uploadFile.getExt());if (!file.getParentFile().exists()) {file.getParentFile().mkdir();}OutputStream output = null;try {output = new FileOutputStream(file);output.write(this.uploadFile.getContentData());return true;} catch (Exception e) {throw e;} finally {output.close();}}}Android客户端,Socket02_Activity.java
package com.iflytek.demo;import java.io.BufferedReader;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.InputStream;import java.io.InputStreamReader;import java.io.ObjectOutputStream;import java.net.Socket;import android.app.Activity;import android.os.AsyncTask;import android.os.Bundle;import android.os.Environment;import android.os.Handler;import android.os.Message;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;import com.iflytek.util.UploadFile;public class Socket02_Activity extends Activity {private Button send = null;private TextView info = null;private static final int FINISH = 0;private Handler myHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case FINISH:String result = msg.obj.toString(); // 取出数据if ("true".equals(result)) {Socket02_Activity.this.info.setText("操作成功!");} else {Socket02_Activity.this.info.setText("操作失败!");}break;}}};/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);this.send = (Button) super.findViewById(R.id.send);this.info = (TextView) super.findViewById(R.id.info);this.send.setOnClickListener(new SendOnClickListener());}/** ** @author xdwang ** @create 2012-11-16 下午10:44:57 ** @email:xdwangiflytek@gmail.com ** @description UploadFile封装的数据通过ObjectOutputStream发送到服务器,服务器返回true or flase **/private class SendOnClickListener implements OnClickListener {@Overridepublic void onClick(View v) {try {final AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {@Overrideprotected void onPostExecute(String result) {}@Overrideprotected void onPreExecute() {super.onPreExecute();}@Overrideprotected String doInBackground(Void... arg0) {try {final Socket client = new Socket("10.0.0.3", 8889);// 指定服务器final BufferedReader buf = new BufferedReader(new InputStreamReader(client.getInputStream())); // 缓冲区读取返回的数据new Thread(new Runnable() {// 创建线程对象@Overridepublic void run() {try {ObjectOutputStream oos = new ObjectOutputStream(client.getOutputStream());// 对象输出流UploadFile myFile = SendOnClickListener.this.getUploadFile();// 取得封装的数据oos.writeObject(myFile);// 输出对象String str = buf.readLine(); // 读取返回数据oos.close();Message msg = Socket02_Activity.this.myHandler.obtainMessage(FINISH,str);Socket02_Activity.this.myHandler.sendMessage(msg);buf.close();client.close();} catch (Exception e) {e.printStackTrace();}}}).start();} catch (Exception e) {// TODO: handle exception}return null;}};task.execute();} catch (Exception e) {e.printStackTrace();}}/** * @descrption 封装数据的方法 * @author xdwang * @create 2012-11-15下午10:46:06 * @return * @throws Exception */private UploadFile getUploadFile() throws Exception {UploadFile myFile = new UploadFile();// 上传封装myFile.setTitle("Java"); // 设置标题myFile.setMimeType("image/jpeg"); // 文件的类型File file = new File(Environment.getExternalStorageDirectory().toString() + File.separator + "java.jpg");// 这里不判断SDCard了InputStream input = null;// 输入流读取try {input = new FileInputStream(file); // 从文件中读取ByteArrayOutputStream bos = new ByteArrayOutputStream();// 字节流byte data[] = new byte;// 开辟读取空间int len = 0;while ((len = input.read(data)) != -1) {// 循环读取bos.write(data, 0, len);// 保存数据}myFile.setContentData(bos.toByteArray());// 保存所有数据myFile.setContentLength(file.length());// 取得文件大小myFile.setExt("jpg");// 文件后缀名} catch (Exception e) {throw e;} finally {input.close();}return myFile;}}}
页:
[1]