项目须要是通过WIFI建立手机和PC的通信,然后自己定义一个简单的协议对要传输的文件进行校验,传输的文件是2张3M的图片,要求考虑网络中断情况处理。

我这里採用的是非堵塞socket来实现的,之前查过非常多资料,认为这样的比較方便,其有用传统的那种socket也是能够实现的,至于堵塞问题,能够开两个线程。这样保证读取不是同一个线程,也就能够解决。

程序大致是这种流程,手机端发送一个“filename”字符串给PC,PC校验字符串后返回文件名称。然后手机端再把接收到的文件名称发送给PC端。进行校验,假设PC端校验成功,那么PC端就開始传输这个文件给手机端。手机端就接收这个文件。

至于网络中断的问题,后来发现,仅仅要在服务端发送文件的那一段程序加入try-catch,捕获这个异常,这样服务端的程序就不会死掉,进入等待。等到手机再次和PC端建立连接。那么就能够又一次发送文件。这里是重传,而不是续传,后来想过。也仅仅有6M,实际測试过。大概2-3秒就能够传完。重传和续传意义不大,所以就简单的重传了。

程序例如以下:

PC端:

public class MyServer {
private final static Logger logger = Logger.getLogger(MyServer.class.getName()); public static void main(String[] args) {
Selector selector = null;
ServerSocketChannel serverSocketChannel = null; try {
selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.socket().setReuseAddress(true);
serverSocketChannel.socket().bind(new InetSocketAddress(1991));
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (selector.select() > 0) {
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey readyKey = it.next();
it.remove(); SocketChannel socketChannel = null;
String string = "";
try {
socketChannel = ((ServerSocketChannel) readyKey.channel()).accept();
string = receiveData(socketChannel);
logger.log(Level.INFO, string);
if(string.equals("filename")){
File f= new File("D:/chz.jpg");
if (f.exists() && f.isFile()){
sendData(socketChannel, "chz.jpg");
}else{
logger.info("file doesn't exist or is not a file");
}
}
if(string.equals("chz.jpg")){
sendFile(socketChannel, new File("D:/chz.jpg"));
}
}catch(Exception ex){
logger.log(Level.SEVERE, "1", ex);
} finally {
try {
socketChannel.close();
} catch(Exception ex) {
logger.log(Level.SEVERE, "2", ex);
}
}
}
}
} catch (ClosedChannelException ex) {
logger.log(Level.SEVERE, "3", ex);
} catch (IOException ex) {
logger.log(Level.SEVERE, "4", ex);
} finally {
try {
selector.close();
} catch(Exception ex) {
logger.log(Level.SEVERE, "5", ex);
}
try {
serverSocketChannel.close();
} catch(Exception ex) {
logger.log(Level.SEVERE, "6", ex);
}
}
} private static String receiveData(SocketChannel socketChannel) throws IOException {
String string = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteBuffer buffer = ByteBuffer.allocate(1024); try {
byte[] bytes;
int size = 0;
while ((size = socketChannel.read(buffer)) >= 0) {
buffer.flip();
bytes = new byte[size];
buffer.get(bytes);
baos.write(bytes);
buffer.clear();
}
bytes = baos.toByteArray();
string = new String(bytes);
}catch(Exception ex){
logger.log(Level.SEVERE, "7", ex);
}finally {
try {
baos.close();
} catch(Exception ex) {
logger.log(Level.SEVERE, "8", ex);
}
}
return string;
} private static void sendData(SocketChannel socketChannel, String string) throws IOException {
byte[] bytes = string.getBytes();
ByteBuffer buffer = ByteBuffer.wrap(bytes);
socketChannel.write(buffer);
socketChannel.socket().shutdownOutput();
} private static void receiveFile(SocketChannel socketChannel, File file) throws IOException {
FileOutputStream fos = null;
FileChannel channel = null; try {
fos = new FileOutputStream(file);
channel = fos.getChannel();
ByteBuffer buffer = ByteBuffer.allocateDirect(1024); int size = 0;
while ((size = socketChannel.read(buffer)) != -1) {
buffer.flip();
if (size > 0) {
buffer.limit(size);
channel.write(buffer);
buffer.clear();
}
}
}catch(Exception ex){
logger.log(Level.SEVERE, "9", ex);
} finally {
try {
channel.close();
} catch(Exception ex) {
logger.log(Level.SEVERE, "10", ex);
}
try {
fos.close();
} catch(Exception ex) {
logger.log(Level.SEVERE, "11", ex);
}
}
} private static void sendFile(SocketChannel socketChannel, File file) throws IOException {
FileInputStream fis = null;
FileChannel channel = null;
try {
fis = new FileInputStream(file);
channel = fis.getChannel();
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
int size = 0;
while ((size = channel.read(buffer)) != -1) {
buffer.rewind();
buffer.limit(size);
socketChannel.write(buffer);
buffer.clear();
}
socketChannel.socket().shutdownOutput();
}catch(Exception ex){
logger.log(Level.SEVERE, "12", ex);
} finally {
try {
channel.close();
} catch(Exception ex) {
logger.log(Level.SEVERE, "13", ex);
}
try {
fis.close();
} catch(Exception ex) {
logger.log(Level.SEVERE, "14", ex);
}
}
}
}

ANDROID端:

public class MainActivity extends Activity {

	private Button mButton;
private EditText et;
private static String string;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main); et = (EditText)findViewById(R.id.edittext1);
et.setText("192.168.1.214");
mButton = (Button)findViewById(R.id.button1);
mButton.setOnClickListener(new OnClickListener() { @Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
string = et.getText().toString();
new Thread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
SocketChannel socketChannel = null;
try {
socketChannel = SocketChannel.open();
SocketAddress socketAddress = new InetSocketAddress(string, 1991);
socketChannel.connect(socketAddress); sendData(socketChannel, "filename");
String string = "";
string = receiveData(socketChannel);
if(!string.isEmpty()){
socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("192.168.1.214", 1991));
sendData(socketChannel, string);
receiveFile(socketChannel, new File("sdcard/afile/"+string));
}
} catch (Exception ex) {
Log.i("chz", null, ex);
} finally {
try {
socketChannel.close();
} catch(Exception ex) {}
}
}
}).start();
}
}); } private void sendData(SocketChannel socketChannel, String string) throws IOException {
byte[] bytes = string.getBytes();
ByteBuffer buffer = ByteBuffer.wrap(bytes);
socketChannel.write(buffer);
socketChannel.socket().shutdownOutput();
} private String receiveData(SocketChannel socketChannel) throws IOException {
String string = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream(); try {
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
byte[] bytes;
int count = 0;
while ((count = socketChannel.read(buffer)) >= 0) {
buffer.flip();
bytes = new byte[count];
buffer.get(bytes);
baos.write(bytes);
buffer.clear();
}
bytes = baos.toByteArray();
string = new String(bytes);
// socketChannel.socket().shutdownInput();
} finally {
try {
baos.close();
} catch(Exception ex) {}
}
return string;
} private static void sendFile(SocketChannel socketChannel, File file) throws IOException {
FileInputStream fis = null;
FileChannel channel = null;
try {
fis = new FileInputStream(file);
channel = fis.getChannel();
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
int size = 0;
while ((size = channel.read(buffer)) != -1) {
buffer.rewind();
buffer.limit(size);
socketChannel.write(buffer);
buffer.clear();
}
socketChannel.socket().shutdownOutput();
} finally {
try {
channel.close();
} catch(Exception ex) {}
try {
fis.close();
} catch(Exception ex) {}
}
} private static void receiveFile(SocketChannel socketChannel, File file) throws IOException {
FileOutputStream fos = null;
FileChannel channel = null; try {
fos = new FileOutputStream(file);
channel = fos.getChannel();
ByteBuffer buffer = ByteBuffer.allocateDirect(1024); int size = 0;
while ((size = socketChannel.read(buffer)) != -1) {
buffer.flip();
if (size > 0) {
buffer.limit(size);
channel.write(buffer);
buffer.clear();
}
}
} finally {
try {
channel.close();
} catch(Exception ex) {}
try {
fos.close();
} catch(Exception ex) {}
}
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}

番外:事实上做这个文件传输遇到的最头痛的问题不是程序难不难写。而是wifi通信的建立。最初我是用自己win7的电脑连路由器。然后手机也连路由器做的測试,没有问题。但是后来项目需求是下位机是一台XP的电脑。并且要求点对点建立wifi,所以仅仅能有一端设成wifi热点。还有一端连接这个热点。设想非常完美,然后找了实验室唯一一台XP电脑測试了两天,都没有可以让我手机连上PC。后来各种问,才知道XP不支持为android创wifi热点,真心坑呀。然后我就想反过来做呗,手机建wifi热点,电脑连。耶果然连上了,但是。明明写好的程序,各种执行不了,最后手机巨热,(我心痛死我的小米。求不黑小米。真心一直用小米,仅仅是导师不给配开发手机,仅仅能用自己手机,哎)所以直接pass这个想法,最后百度了一下。貌似可以接外接硬件设备,例如说360随身wifi硬件,嗯导师最终答应淘宝买一个来測试下,今天买吧。

哦,整个程序參考了两位大神博客:http://www.cnblogs.com/hongten/archive/2012/04/29/java_socket.html

http://blog.csdn.net/kongxx/article/details/7288896尤其是后面这位大神的一个专栏专门讲java socket的。讲得非常好。

这个文件传输的整个project地址:http://download.csdn.net/detail/u012321815/8047863



非堵塞socket实现android手机与PC的文件传输的更多相关文章

  1. 基于C/S模式的android手机与PC机通信系统的开发

    原文链接: http://blog.csdn.net/nupt123456789/article/details/8213486 基于C/S模式的android手机与PC机通信系统的开发 作者:郑海波 ...

  2. 我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重启的功能(三)Android客户端功能实现

    我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重启的功能(一)PC服务器端(地址:http://blog.csdn.net/ouyang_pen ...

  3. android手机连接PC无法正常安装驱动

    工作当中我们经常会遇到Android手机连接PC的时候无法正确安装驱动,或者安装失败.当然找到正确的驱动文件时首选的解决方案,如果正确的驱动文件依旧无法安装成功我们可以打开我的电脑-->属性-- ...

  4. PC端轻松控制Android手机,PC Control Andoroid,PC控制安卓手机

    记录此次经历的目的是帮助需要的人或下次使用时少走弯路,我为此试用了不少工具及方法,因为追求免费,像"Weak Control:在PC上控制你的Android手机"还要收费的我就不弄 ...

  5. Android手机播放电脑视频文件-屌丝必备

    今天早上一到办公室,照常打开博客园看文章,看到有一片文章是用  http://www.cnblogs.com/wdfrog/p/3738180.html 看到这哥们实现的方法好复杂,又是配置电脑端,又 ...

  6. linux网络环境下socket套接字编程(UDP文件传输)

    今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...

  7. 基于Socket的Android手机视频实时传输

    首先,简单介绍一下原理.主要是在手机客户端 (Android)通过实现Camera.PreviewCallback接口,在其onPreviewFrame重载函数里面获取摄像头当前图像数据, 然后通过S ...

  8. 我的Android进阶之旅------&gt;Android实现用Android手机控制PC端的关机和重新启动的功能(二)Androidclient功能展示

    Androidclient的实现思路大致例如以下: 1.首先扫描局域网内全部PC,看是否有PC端的server在执行并监听30000port. watermark/2/text/aHR0cDovL2J ...

  9. socket编程 —— 非阻塞socket (转)---例子已上传至文件中

    在上一篇文章 <socket编程——一个简单的例子> http://blog.csdn.net/wind19/archive/2011/01/21/6156339.aspx 中写了一个简单 ...

随机推荐

  1. sqlserver access 多数据库操作

    今天搞了一天的事情, 更新 ACCESS 數據庫 ,要從  SQL SERVER 2008數據庫中  查詢資料.沒找到資料 只能自己做了. 首先查找一下 ,如何 用SQL  語句 select *   ...

  2. 五子棋-b

    五子棋是程序猿比较熟悉的一款小游戏,相信很多人大学时期就用多种语言写过五子棋小游戏.笔者工作闲暇之余,试着用OC实现了一下,在这里给大家分享一下.有不足之处,欢迎大家提供建议和指点!!!GitHub源 ...

  3. Memcached(三)Memcached配置参数初解

    一.基本参数在我们第一次安装Memcached时,一般都是用过这个命令: memcached -m 512 -u root -d -l 127.0.0.1 -p 11211 我们先来解释这几个参数的含 ...

  4. caffe之(一)卷积层

    在caffe中,网络的结构由prototxt文件中给出,由一些列的Layer(层)组成,常用的层如:数据加载层.卷积操作层.pooling层.非线性变换层.内积运算层.归一化层.损失计算层等:本篇主要 ...

  5. SQL 各种连接:内连接,外连接(左外,右外,完全外)

    在讲述之前,假设有如下两个表EMP, DEPT, 并且他们数据如下:

  6. python中的__init__ 、__new__、__call__等内置函数的剖析

    1.__new__(cls, *args, **kwargs)   创建对象时调用,返回当前对象的一个实例;注意:这里的第一个参数是cls即class本身2.__init__(self, *args, ...

  7. capitalize()在Python中含义

    Python为string对象提供了转换大小写的方法:upper() 和 lower(). 还不止这些,Python还为我们提供了首字母大写,其余小写的capitalize()方法, 以及所有单词首字 ...

  8. Matlab中Rand()函数用法

    一.理论准备 matlab函数randn:产生均值为0,方差 σ^2 = 1,标准差σ = 1的正态分布的随机数或矩阵的函数. 用法:Y = randn(n),返回一个n*n的随机项的矩阵.如果n不是 ...

  9. BZOJ 1574: [Usaco2009 Jan]地震损坏Damage

    Description 农夫John的农场遭受了一场地震.有一些牛棚遭到了损坏,但幸运地,所有牛棚间的路经都还能使用. FJ的农场有P(1 <= P <= 30,000)个牛棚,编号1.. ...

  10. IP处理函数inet_aton()和inet_ntoa(),inet_pton,inet_ntop

    inet_ntoa: 功能: 将一个IP转换成一个互联网标准点分格式的字符串. 原型: char FAR * inet_ntoa( struct in_addr in); 返回值: 如果正确,返回一个 ...