`

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() {
		@Override
		public 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. */
	@Override
	public 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 {
		@Override
		public void onClick(View v) {

			final AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {

				@Override
				protected void onPostExecute(String result) {
					final String temp = result;
					Thread thread = new Thread(new Runnable() {
						@Override
						public void run() {
							Message msg = new Message();
							msg.what = 1;
							msg.obj = temp;
							handler.sendMessage(msg);
						}
					});
					thread.start();
				}

				@Override
				protected void onPreExecute() {
					super.onPreExecute();
				}

				@Override
				protected 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) {//通过构造方法设置Socket
		this.client = client;
		System.out.println("新的客户端连接...");
	}

	@Override
	public 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() {
		@Override
		public 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. */
	@Override
	public 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 {
		@Override
		public void onClick(View v) {
			try {

				final AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {

					@Override
					protected void onPostExecute(String result) {
					}

					@Override
					protected void onPreExecute() {
						super.onPreExecute();
					}

					@Override
					protected 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() {// 创建线程对象

										@Override
										public 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[1024];// 开辟读取空间
				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;
		}

	}

}
分享到:
评论

相关推荐

    Best-HTTP2-2.6.2-for-Unity3D-2021

    Socket通信:BestHTTP还提供了对Socket通信的支持,允许通过TCP或UDP协议与服务器进行底层的数据交换。 支持缓存和压缩:BestHTTP支持缓存机制。 强大的回调和事件机制:BestHTTP提供了丰富的回调和事件处理程序,...

    Cocos2d-x实战 C++卷,完整扫描版

    第三篇数据与网络,即第13章~第17章,内容包括Cocos2d-x中使用的数据容器类、数据持久化、数据交换格式、基于HTTP网络通信和基于Node.js的Socket.IO网络通信。 第四篇设计与优化,即第18章~第20章,内容包括Cocos...

    Android开发案例驱动教程 配套代码

    15.2 网络通信技术与实现 374 15.2.1 网络通信技术介绍 376 15.2.2 Java URL类实现方式 377 15.2.3 Apache HttpClient实现方式 378 15.3 数据交换格式 380 15.3.1 纯文本格式 381 15.3.2 XML格式 381 15.3.3 ...

    Android中Socket大文件断点上传示例

    所谓Socket通常也称作“套接字”,用于描述IP地址和端口,是一个通信连的句柄,应用程序通常通过“套接字”向网络发送请求或者应答网络请求,它就是网络通信过程中端点的抽象表示。它主要包括以下两个协议: TCP ...

    疯狂Android讲义源码

     13.1 基于TCP协议的网络通信 477  13.1.1 TCP协议基础 477  13.1.2 使用ServerSocket创建  TCP服务器端 478  13.1.3 使用Socket进行通信 479  13.1.4 加入多线程 483  13.2 使用URL访问网络资源 488  ...

    疯狂Android讲义.part2

    13.1 基于TCP协议的网络通信 477 13.1.1 TCP协议基础 477 13.1.2 使用ServerSocket创建TCP 服务器端 478 13.1.3 使用Socket进行通信 479 13.1.4 加入多线程 483 13.2 使用URL访问网络资源 489 13.2.1 使用URL读取...

    疯狂Android讲义.part1

    13.1 基于TCP协议的网络通信 477 13.1.1 TCP协议基础 477 13.1.2 使用ServerSocket创建TCP 服务器端 478 13.1.3 使用Socket进行通信 479 13.1.4 加入多线程 483 13.2 使用URL访问网络资源 489 13.2.1 使用URL读取...

    JAVA五子棋手机网络对战游戏的设计与实现.rar

    Socket编程:用于实现客户端与服务器之间的网络通信,确保玩家可以进行实时对战。 五子棋算法:实现游戏规则、胜负判断等核心逻辑。 功能设计: 用户登录注册:玩家可以注册账号并登录游戏,也可以选择匿名游戏。 ...

    Socketer:一个简单的socket调试工具。-开源

    当开发人员开发需要套接字和网络通信的功能时,能够验证他们的代码实际上正在建立网络连接并且代码实际上正在处理网络上的数据交换非常有用。 Socketer 可以在用户选择的端口上打开服务器套接字并显示在该端口上...

    JAVA上百实例源码以及开源项目源代码

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    Android实现蓝牙(BlueTooth)设备检测连接

    无论是WIFI还是4G网络,建立网络连接后都是访问互联网资源,并不能直接访问局域网资源。比如两个人在一起,A要把手机上的视频传给B,通常情况是打开手机QQ,通过QQ传送文件给对方。不过上传视频很耗流量,如果现场...

    JAVA上百实例源码以及开源项目

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    WebSocket客户端和服务端实例源码

    基于 Flash,AdobeFlash 通过自己的 Socket 实现完成数据交换,再利用 Flash 暴露出相应的接口为 JavaScript 调用,从而达到实时传输目的。此方式比轮询要高效,且因为 Flash 安装率高,应用场景比较广泛,但在移动...

Global site tag (gtag.js) - Google Analytics