小猪的Android入门之路 Day 8 part 6

Android网络编程浅析——Socket网络编程初涉

——转载请注明出处:coder-pig





本节引言

终于迎来了Android网络编程的最后一节:Android中的Socket编程,在这一节中我们

首先需要对TCP/IP协议的概念,以及Socket的相关知识进行介绍,接着介绍下Socket的简单

流程,最后使用Socket创建简单的Android聊天室以及Socket实现大文件的断点上传

好了,开始本节内容!



本节学习路线图:




正文:


TCP/IP和Socket的简单了解:





Socket通信的基本流程:




简单的Socket网络聊天室实例:

相信学过Java的朋友在Java网络那里就已经学过使用socket搭建简单的聊天室了;

我们首先需要创建一个作为服务端的Java app,和Java的是一样的;

接着我们需要创建一个Android app用于发送与显示聊天信息,这里可别忘了以下两点:

①Android 4.0后是不允许在主线程中进行网络操作的,所以需要另外开辟一条线程

②为了保证Android线程安全,对于界面的修改,只能在主线程中进行;或者通过handler,在

子线程中调用handler发送信息的方法,调用handler完成界面组件的修改



为了照顾一些对Java不熟的朋友,先写个简单的socket连服务端的程序,给大家熟悉熟悉

运行效果如下:


代码如下:

Java服务端:

Server.java

[java]   view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.jay.pc.demo;  
  2.   
  3. import java.io.BufferedWriter;  
  4. import java.io.IOException;  
  5. import java.io.OutputStreamWriter;  
  6. import java.net.ServerSocket;  
  7. import java.net.Socket;  
  8.   
  9. public class Server {  
  10.     //定义端口号  
  11.     private static final int PORT = 9999;  
  12.       
  13.     public static void main(String[] args) {  
  14.           
  15.         try  
  16.         {  
  17.             ServerSocket server = new ServerSocket(PORT);  
  18.             //这里堵塞,无限循环,调用accept方法,等待客户端连接  
  19.             while(true)  
  20.             {  
  21.                 Socket socket = server.accept();  
  22.                 //获取输出流  
  23.                 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));  
  24.                 //写字符串,出现中文要进行转码哦,不然会出现乱码的情况                  
  25.                 writer.write(new String("连接服务器成功那么这个时候问题来了?".getBytes("UTF-8"),"GBK"));  
  26.                 writer.flush();  
  27.                 writer.close();               
  28.             }     
  29.         }catch(IOException e){e.printStackTrace();}  
  30.           
  31.     }  
  32.       
  33. }  

Android客户端:

activty_main.xml布局文件:

[html]   view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:id="@+id/LinearLayout1"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     android:orientation="vertical"  
  7.     tools:context="com.jay.example.socketdemo1.MainActivity" >  
  8.   
  9.     <Button  
  10.         android:id="@+id/btnlogin"  
  11.         android:layout_width="wrap_content"  
  12.         android:layout_height="wrap_content"  
  13.         android:text="连接服务器" />  
  14.       
  15.     <TextView   
  16.         android:layout_width="match_parent"  
  17.         android:layout_height="match_parent"  
  18.         android:id="@+id/txtshow"      
  19.     />  
  20.   
  21.       
  22. </LinearLayout>  




MainActivty.java

[java]   view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.jay.example.socketdemo1;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.InputStreamReader;  
  5. import java.net.Socket;  
  6.   
  7. import android.app.Activity;  
  8. import android.os.Bundle;  
  9. import android.os.Handler;  
  10. import android.os.Message;  
  11. import android.util.Log;  
  12. import android.view.View;  
  13. import android.view.View.OnClickListener;  
  14. import android.widget.Button;  
  15. import android.widget.TextView;  
  16.   
  17.   
  18. public class MainActivity extends Activity {  
  19.   
  20.     private Button btnlogin;  
  21.     private TextView txtshow;  
  22.     private String send;  
  23.       
  24.     //定义ip地址与端口号常量  
  25.     private static final String HOST = "192.168.27.172";  
  26.     private static final int PORT = 9999;  
  27.       
  28.      // 定义Handler对象    
  29.     private Handler handler = new Handler() {    
  30.         @Override    
  31.         // 当有消息发送出来的时候就执行Handler的这个方法    
  32.         public void handleMessage(Message msg) {    
  33.             super.handleMessage(msg);    
  34.             // 处理UI    
  35.             txtshow.setText(send);    
  36.         }    
  37.     };    
  38.       
  39.       
  40.     @Override  
  41.     protected void onCreate(Bundle savedInstanceState) {  
  42.         super.onCreate(savedInstanceState);  
  43.         setContentView(R.layout.activity_main);  
  44.           
  45.         btnlogin = (Button) findViewById(R.id.btnlogin);  
  46.         txtshow = (TextView) findViewById(R.id.txtshow);  
  47.         btnlogin.setOnClickListener(new AcceptListener());  
  48.           
  49.     }  
  50.       
  51.       
  52.     class AcceptListener implements View.OnClickListener  
  53.     {  
  54.         @Override  
  55.         public void onClick(View v) {  
  56.             new Thread()  
  57.             {  
  58.                 public void run()   
  59.                 {  
  60.                     try  
  61.                     {  
  62.                         Socket socket = new Socket(HOST,PORT);  
  63.                         BufferedReader br = new BufferedReader(    
  64.                                 new InputStreamReader(socket.getInputStream()));  
  65.                         send = br.readLine();  
  66.                         br.close();  
  67.                     }catch(Exception e){e.printStackTrace();}  
  68.                     handler.sendEmptyMessage(0);  
  69.                 };  
  70.             }.start();  
  71.               
  72.         }  
  73.     }  
  74.   
  75.       
  76. }  


好了,估计大家看完上面这个代码以后,对socket聊天室的大概原理流程都有了初步的了解了吧,

那么我们就继续开发一个可以多个用户同时聊天的简单聊天室吧!效果图如下:


接着开启两个客户端,进行聊天,运行客户端后,控制台可以查看到当前在线的有两个用户,以及他们的ip


接着我们打开两个模拟器,进行聊天,从图中我们可以看到两个模拟器都是实时聊天的,发送后即时显示!

最后,当我们输如bye的时候,客户端会断开与服务端的连接,在另一客户端中也可以看到,某某退出的信息!


同样的,在服务端的Console控制台上也可以看到聊天记录:




看完效果图,是不是有点心动了,好的,接下来我们就要用代码去实现了

服务端:server.java



安卓端(客户端)





*Android使用Socket实现大文件的断点续传

前面我们已经学过使用Http协议来完成文件的上传,但是这样上传有一个弊病就是,对于大文件来说

显得有点坑爹,万一传到一半哐当,手机没电关机了,那么就下次又必须重新上传了,这样显然是会引起

用户不满的(用户是很急躁的),于是乎我们要使用socket来完成大文件的上传操作,并且加入断点功能

和前面的多线程断点下载有点类似,笔者水平有限,而且鉴于时间关系,也不自己敲出整个程序来了;

这里直接用传智播客老师——黎明活老师提供的代码了,为了方便大家掌握使用,也会解析下程序!

好了,那么先看下效果先!

先把要上传的文件拖拉到sd卡目录下,接着先开启服务端,然后再运行客户端,点击上传!


上传完成后,来到server的工程路径下,可以看到在file路径下可以找到我们上传的文件以及一个日志文件


当然,你也可以下到一半然后退出模拟器,再次上传文件,验证断点上传的功能是否有效!


好了,下面就让我们来解析下实现的代码!

只是大概地解释下流程,还需自己看看代码哦!



参考代码如下:

首先是服务端和客户端都有的流解析类:

StreamTool.java

[java]   view plain copy print ?
  1. import java.io.ByteArrayOutputStream;  
  2. import java.io.File;  
  3. import java.io.FileOutputStream;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6. import java.io.PushbackInputStream;  
  7.   
  8. public class StreamTool {  
  9.        
  10.      public static void save(File file, byte[] data) throws Exception {  
  11.          FileOutputStream outStream = new FileOutputStream(file);  
  12.          outStream.write(data);  
  13.          outStream.close();  
  14.      }  
  15.        
  16.      public static String readLine(PushbackInputStream in) throws IOException {  
  17.             char buf[] = new char[128];  
  18.             int room = buf.length;  
  19.             int offset = 0;  
  20.             int c;  
  21. loop:       while (true) {  
  22.                 switch (c = in.read()) {  
  23.                     case -1:  
  24.                     case '\n':  
  25.                         break loop;  
  26.                     case '\r':  
  27.                         int c2 = in.read();  
  28.                         if ((c2 != '\n') && (c2 != -1)) in.unread(c2);  
  29.                         break loop;  
  30.                     default:  
  31.                         if (--room < 0) {  
  32.                             char[] lineBuffer = buf;  
  33.                             buf = new char[offset + 128];  
  34.                             room = buf.length - offset - 1;  
  35.                             System.arraycopy(lineBuffer, 0, buf, 0, offset);  
  36.                              
  37.                         }  
  38.                         buf[offset++] = (char) c;  
  39.                         break;  
  40.                 }  
  41.             }  
  42.             if ((c == -1) && (offset == 0)) return null;  
  43.             return String.copyValueOf(buf, 0, offset);  
  44.     }  
  45.        
  46.     /** 
  47.     * 读取流 
  48.     * @param inStream 
  49.     * @return 字节数组 
  50.     * @throws Exception 
  51.     */  
  52.     public static byte[] readStream(InputStream inStream) throws Exception{  
  53.             ByteArrayOutputStream outSteam = new ByteArrayOutputStream();  
  54.             byte[] buffer = new byte[1024];  
  55.             int len = -1;  
  56.             while( (len=inStream.read(buffer)) != -1){  
  57.                 outSteam.write(buffer, 0, len);  
  58.             }  
  59.             outSteam.close();  
  60.             inStream.close();  
  61.             return outSteam.toByteArray();  
  62.     }  
  63. }  


服务端:

FileServer.java

[java]   view plain copy print ?
  1. package com.jay.pc.example;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.FileOutputStream;  
  6. import java.io.IOException;  
  7. import java.io.OutputStream;  
  8. import java.io.PushbackInputStream;  
  9. import java.io.RandomAccessFile;  
  10. import java.net.ServerSocket;  
  11. import java.net.Socket;  
  12. import java.text.SimpleDateFormat;  
  13. import java.util.Date;  
  14. import java.util.HashMap;  
  15. import java.util.Map;  
  16. import java.util.Properties;  
  17. import java.util.concurrent.ExecutorService;  
  18. import java.util.concurrent.Executors;  
  19.   
  20.   
  21.   
  22. public class FileServer {  
  23.       
  24.      private ExecutorService executorService;//线程池  
  25.      private int port;//监听端口  
  26.      private boolean quit = false;//退出  
  27.      private ServerSocket server;  
  28.      private Map<Long, FileLog> datas = new HashMap<Long, FileLog>();//存放断点数据  
  29.        
  30.      public FileServer(int port){  
  31.          this.port = port;  
  32.          //创建线程池,池中具有(cpu个数*50)条线程  
  33.          executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 50);  
  34.      }  
  35.      /** 
  36.       * 退出 
  37.       */  
  38.      public void quit(){  
  39.         this.quit = true;  
  40.         try {  
  41.             server.close();  
  42.         } catch (IOException e) {  
  43.         }  
  44.      }  
  45.      /** 
  46.       * 启动服务 
  47.       * @throws Exception 
  48.       */  
  49.      public void start() throws Exception{  
  50.          server = new ServerSocket(port);  
  51.          while(!quit){  
  52.              try {  
  53.                Socket socket = server.accept();  
  54.                //为支持多用户并发访问,采用线程池管理每一个用户的连接请求  
  55.                executorService.execute(new SocketTask(socket));  
  56.              } catch (Exception e) {  
  57.                //  e.printStackTrace();  
  58.              }  
  59.          }  
  60.      }  
  61.        
  62.      private final class SocketTask implements Runnable{  
  63.         private Socket socket = null;  
  64.         public SocketTask(Socket socket) {  
  65.             this.socket = socket;  
  66.         }  
  67.           
  68.         public void run() {  
  69.             try {  
  70.                 System.out.println("accepted connection "+ socket.getInetAddress()+ ":"+ socket.getPort());  
  71.                 PushbackInputStream inStream = new PushbackInputStream(socket.getInputStream());  
  72.                 //得到客户端发来的第一行协议数据:Content-Length=143253434;filename=xxx.3gp;sourceid=  
  73.                 //如果用户初次上传文件,sourceid的值为空。  
  74.                 String head = StreamTool.readLine(inStream);  
  75.                 System.out.println(head);  
  76.                 if(head!=null){  
  77.                     //下面从协议数据中提取各项参数值  
  78.                     String[] items = head.split(";");  
  79.                     String filelength = items[0].substring(items[0].indexOf("=")+1);  
  80.                     String filename = items[1].substring(items[1].indexOf("=")+1);  
  81.                     String sourceid = items[2].substring(items[2].indexOf("=")+1);        
  82.                     long id = System.currentTimeMillis();//生产资源id,如果需要唯一性,可以采用UUID  
  83.                     FileLog log = null;  
  84.                     if(sourceid!=null && !"".equals(sourceid)){  
  85.                         id = Long.valueOf(sourceid);  
  86.                         log = find(id);//查找上传的文件是否存在上传记录  
  87.                     }  
  88.                     File file = null;  
  89.                     int position = 0;  
  90.                     if(log==null){//如果不存在上传记录,为文件添加跟踪记录  
  91.                         String path = new SimpleDateFormat("yyyy/MM/dd/HH/mm").format(new Date());  
  92.                         File dir = new File("file/"+ path);  
  93.                         if(!dir.exists()) dir.mkdirs();  
  94.                         file = new File(dir, filename);  
  95.                         if(file.exists()){//如果上传的文件发生重名,然后进行改名  
  96.                             filename = filename.substring(0, filename.indexOf(".")-1)+ dir.listFiles().length+ filename.substring(filename.indexOf("."));  
  97.                             file = new File(dir, filename);  
  98.                         }  
  99.                         save(id, file);  
  100.                     }else{// 如果存在上传记录,读取已经上传的数据长度  
  101.                         file = new File(log.getPath());//从上传记录中得到文件的路径  
  102.                         if(file.exists()){  
  103.                             File logFile = new File(file.getParentFile(), file.getName()+".log");  
  104.                             if(logFile.exists()){  
  105.                                 Properties properties = new Properties();  
  106.                                 properties.load(new FileInputStream(logFile));  
  107.                                 position = Integer.valueOf(properties.getProperty("length"));//读取已经上传的数据长度  
  108.                             }  
  109.                         }  
  110.                     }  
  111.                       
  112.                     OutputStream outStream = socket.getOutputStream();  
  113.                     String response = "sourceid="+ id+ ";position="+ position+ "\r\n";  
  114.                     //服务器收到客户端的请求信息后,给客户端返回响应信息:sourceid=1274773833264;position=0  
  115.                     //sourceid由服务器端生成,唯一标识上传的文件,position指示客户端从文件的什么位置开始上传  
  116.                     outStream.write(response.getBytes());  
  117.                       
  118.                     RandomAccessFile fileOutStream = new RandomAccessFile(file, "rwd");  
  119.                     if(position==0) fileOutStream.setLength(Integer.valueOf(filelength));//设置文件长度  
  120.                     fileOutStream.seek(position);//指定从文件的特定位置开始写入数据  
  121.                     byte[] buffer = new byte[1024];  
  122.                     int len = -1;  
  123.                     int length = position;  
  124.                     while( (len=inStream.read(buffer)) != -1){//从输入流中读取数据写入到文件中  
  125.                         fileOutStream.write(buffer, 0, len);  
  126.                         length += len;  
  127.                         Properties properties = new Properties();  
  128.                         properties.put("length", String.valueOf(length));  
  129.                         FileOutputStream logFile = new FileOutputStream(new File(file.getParentFile(), file.getName()+".log"));  
  130.                         properties.store(logFile, null);//实时记录已经接收的文件长度  
  131.                         logFile.close();  
  132.                     }  
  133.                     if(length==fileOutStream.length()) delete(id);  
  134.                     fileOutStream.close();                    
  135.                     inStream.close();  
  136.                     outStream.close();  
  137.                     file = null;  
  138.                       
  139.                 }  
  140.             } catch (Exception e) {  
  141.                 e.printStackTrace();  
  142.             }finally{  
  143.                 try {  
  144.                     if(socket!=null && !socket.isClosed()) socket.close();  
  145.                 } catch (IOException e) {}  
  146.             }  
  147.         }  
  148.      }  
  149.        
  150.      public FileLog find(Long sourceid){  
  151.          return datas.get(sourceid);  
  152.      }  
  153.      //保存上传记录  
  154.      public void save(Long id, File saveFile){  
  155.          //日后可以改成通过数据库存放  
  156.          datas.put(id, new FileLog(id, saveFile.getAbsolutePath()));  
  157.      }  
  158.      //当文件上传完毕,删除记录  
  159.      public void delete(long sourceid){  
  160.          if(datas.containsKey(sourceid)) datas.remove(sourceid);  
  161.      }  
  162.        
  163.      private class FileLog{  
  164.         private Long id;  
  165.         private String path;  
  166.         public Long getId() {  
  167.             return id;  
  168.         }  
  169.         public void setId(Long id) {  
  170.             this.id = id;  
  171.         }  
  172.         public String getPath() {  
  173.             return path;  
  174.         }  
  175.         public void setPath(String path) {  
  176.             this.path = path;  
  177.         }  
  178.         public FileLog(Long id, String path) {  
  179.             this.id = id;  
  180.             this.path = path;  
  181.         }     
  182.      }  
  183.   
  184. }  


服务端界面类:ServerWindow.java

[java]   view plain copy print ?
  1. package com.jay.pc.example;  
  2.   
  3. import java.awt.BorderLayout;  
  4. import java.awt.Frame;  
  5. import java.awt.Label;  
  6. import java.awt.event.WindowEvent;  
  7. import java.awt.event.WindowListener;  
  8.   
  9. public class ServerWindow extends Frame{  
  10.     private FileServer s = new FileServer(7878);  
  11.     private Label label;  
  12.       
  13.     public ServerWindow(String title){  
  14.         super(title);  
  15.         label = new Label();  
  16.         add(label, BorderLayout.PAGE_START);  
  17.         label.setText("服务器已经启动");  
  18.         this.addWindowListener(new WindowListener() {  
  19.             public void windowOpened(WindowEvent e) {  
  20.                 new Thread(new Runnable() {   
  21.                     public void run() {  
  22.                         try {  
  23.                             s.start();  
  24.                         } catch (Exception e) {  
  25.                             //e.printStackTrace();  
  26.                         }  
  27.                     }  
  28.                 }).start();  
  29.             }  
  30.               
  31.             public void windowIconified(WindowEvent e) {  
  32.             }  
  33.               
  34.             public void windowDeiconified(WindowEvent e) {  
  35.             }  
  36.               
  37.             public void windowDeactivated(WindowEvent e) {  
  38.             }  
  39.               
  40.             public void windowClosing(WindowEvent e) {  
  41.                  s.quit();  
  42.                  System.exit(0);  
  43.             }  
  44.               
  45.             public void windowClosed(WindowEvent e) {  
  46.             }  
  47.               
  48.             public void windowActivated(WindowEvent e) {  
  49.             }  
  50.         });  
  51.     }  
  52.     /** 
  53.      * @param args 
  54.      */  
  55.     public static void main(String[] args) {  
  56.         ServerWindow window = new ServerWindow("文件上传服务端");   
  57.         window.setSize(300300);   
  58.         window.setVisible(true);  
  59.           
  60.     }  
  61.   
  62. }  


客户端(Android端)

布局文件main.xml

[html]   view plain copy print ?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical"  
  4.     android:layout_width="fill_parent"  
  5.     android:layout_height="fill_parent"  
  6.     >  
  7. <TextView    
  8.     android:layout_width="fill_parent"   
  9.     android:layout_height="wrap_content"   
  10.     android:text="@string/filename"  
  11.     />  
  12.       
  13.     <EditText    
  14.     android:layout_width="fill_parent"   
  15.     android:layout_height="wrap_content"   
  16.     android:text="twelve.mp3"  
  17.     android:id="@+id/filename"  
  18.     />  
  19.       
  20.    <Button    
  21.         android:layout_width="wrap_content"   
  22.         android:layout_height="wrap_content"   
  23.         android:text="@string/button"  
  24.         android:id="@+id/button"  
  25.         />  
  26.       
  27.    <Button    
  28.         android:layout_width="wrap_content"   
  29.         android:layout_height="wrap_content"   
  30.         android:text="停止"  
  31.         android:id="@+id/button1"  
  32.         />  
  33.      
  34.     <ProgressBar   
  35.         android:layout_width="fill_parent"   
  36.         android:layout_height="20px"  
  37.         style="?android:attr/progressBarStyleHorizontal"  
  38.         android:id="@+id/uploadbar"  
  39.         />   
  40.     <TextView    
  41.         android:layout_width="fill_parent"   
  42.         android:layout_height="wrap_content"   
  43.         android:gravity="center"  
  44.         android:id="@+id/result"  
  45.         />      
  46. </LinearLayout>  


数据库与数据库操作类:

DBOpenHelper.java

[java]   view plain copy print ?
  1. package cn.itcast.service;  
  2.   
  3. import android.content.Context;  
  4. import android.database.sqlite.SQLiteDatabase;  
  5. import android.database.sqlite.SQLiteOpenHelper;  
  6.   
  7. public class DBOpenHelper extends SQLiteOpenHelper {  
  8.   
  9.     public DBOpenHelper(Context context) {  
  10.         super(context, "itcast.db"null1);  
  11.     }  
  12.   
  13.     @Override  
  14.     public void onCreate(SQLiteDatabase db) {  
  15.         db.execSQL("CREATE TABLE IF NOT EXISTS uploadlog (_id integer primary key autoincrement, path varchar(20), sourceid varchar(20))");  
  16.     }  
  17.   
  18.     @Override  
  19.     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {  
  20.         // TODO Auto-generated method stub  
  21.   
  22.     }  
  23.   
  24. }  


UploadLogService.java

[java]   view plain copy print ?
  1. package cn.itcast.service;  
  2.   
  3. import java.io.File;  
  4.   
  5. import android.content.Context;  
  6. import android.database.Cursor;  
  7. import android.database.sqlite.SQLiteDatabase;  
  8.   
  9. public class UploadLogService {  
  10.     private DBOpenHelper dbOpenHelper;  
  11.       
  12.     public UploadLogService(Context context){  
  13.         dbOpenHelper = new DBOpenHelper(context);  
  14.     }  
  15.       
  16.     public String getBindId(File file){  
  17.         SQLiteDatabase db = dbOpenHelper.getReadableDatabase();  
  18.         Cursor cursor = db.rawQuery("select sourceid from uploadlog where path=?"new String[]{file.getAbsolutePath()});  
  19.         if(cursor.moveToFirst()){  
  20.             return cursor.getString(0);  
  21.         }  
  22.         return null;  
  23.     }  
  24.       
  25.     public void save(String sourceid, File file){  
  26.         SQLiteDatabase db = dbOpenHelper.getWritableDatabase();  
  27.         db.execSQL("insert into uploadlog(path,sourceid) values(?,?)",   
  28.                 new Object[]{file.getAbsolutePath(), sourceid});  
  29.     }  
  30.       
  31.     public void delete(File file){  
  32.         SQLiteDatabase db = dbOpenHelper.getWritableDatabase();  
  33.         db.execSQL("delete from uploadlog where path=?"new Object[]{file.getAbsolutePath()});  
  34.     }  
  35.  }  


主界面:MainActivity.java

[java]   view plain copy print ?
  1. package cn.itcast.upload;  
  2.   
  3. import java.io.File;  
  4. import java.io.OutputStream;  
  5. import java.io.PushbackInputStream;  
  6. import java.io.RandomAccessFile;  
  7. import java.net.Socket;  
  8.   
  9. import cn.itcast.service.UploadLogService;  
  10. import cn.itcast.utils.StreamTool;  
  11.   
  12. import android.app.Activity;  
  13. import android.os.Bundle;  
  14. import android.os.Environment;  
  15. import android.os.Handler;  
  16. import android.os.Message;  
  17. import android.view.View;  
  18. import android.view.View.OnClickListener;  
  19. import android.widget.Button;  
  20. import android.widget.EditText;  
  21. import android.widget.ProgressBar;  
  22. import android.widget.TextView;  
  23. import android.widget.Toast;  
  24.   
  25. public class MainActivity extends Activity {  
  26.     private EditText filenameText;  
  27.     private TextView resultView;  
  28.     private ProgressBar uploadbar;  
  29.     private UploadLogService service;  
  30.     private boolean flag = true;  
  31.     private Handler handler = new Handler(){  
  32.         @Override  
  33.         public void handleMessage(Message msg) {  
  34.             uploadbar.setProgress(msg.getData().getInt("length"));  
  35.             float num = (float)uploadbar.getProgress() / (float)uploadbar.getMax();  
  36.             int result = (int)(num * 100);  
  37.             resultView.setText(result + "%");  
  38.             if(uploadbar.getProgress() == uploadbar.getMax()){  
  39.                 Toast.makeText(MainActivity.this, R.string.success, 1).show();  
  40.             }  
  41.         }  
  42.     };  
  43.       
  44.     @Override  
  45.     public void onCreate(Bundle savedInstanceState) {  
  46.         super.onCreate(savedInstanceState);  
  47.         setContentView(R.layout.main);  
  48.           
  49.         service =  new UploadLogService(this);  
  50.         filenameText = (EditText)findViewById(R.id.filename);  
  51.         resultView = (TextView)findViewById(R.id.result);  
  52.         uploadbar = (ProgressBar)findViewById(R.id.uploadbar);  
  53.         Button button = (Button)findViewById(R.id.button);  
  54.         Button button1 = (Button) findViewById(R.id.button1);  
  55.           
  56.         button1.setOnClickListener(new OnClickListener() {  
  57.               
  58.             @Override  
  59.             public void onClick(View v) {  
  60.                 flag = false;  
  61.                   
  62.             }  
  63.         });  
  64.           
  65.           
  66.         button.setOnClickListener(new View.OnClickListener() {    
  67.             public void onClick(View v) {  
  68.                 String filename = filenameText.getText().toString();  
  69.                 flag = true;  
  70.                 if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){  
  71.                     File file = new File(Environment.getExternalStorageDirectory(), filename);  
  72.                     if(file.exists()){  
  73.                         uploadbar.setMax((int)file.length());  
  74.                         uploadFile(file);  
  75.                     }else{  
  76.                         Toast.makeText(MainActivity.this, R.string.notexsit, 1).show();  
  77.                     }  
  78.                 }else{  
  79.                     Toast.makeText(MainActivity.this, R.string.sdcarderror, 1).show();  
  80.                 }  
  81.             }  
  82.         });  
  83.     }  
  84.   
  85.     private void uploadFile(final File file) {  
  86.         new Thread(new Runnable() {   
  87.             public void run() {  
  88.                 try {  
  89.                     String sourceid = service.getBindId(file);  
  90.                     Socket socket = new Socket("192.168.10.64"7878);  
  91.                     OutputStream outStream = socket.getOutputStream();   
  92.                     String head = "Content-Length="+ file.length() + ";filename="+ file.getName()   
  93.                         + ";sourceid="+(sourceid!=null ? sourceid : "")+"\r\n";  
  94.                     outStream.write(head.getBytes());  
  95.                       
  96.                     PushbackInputStream inStream = new PushbackInputStream(socket.getInputStream());      
  97.                     String response = StreamTool.readLine(inStream);  
  98.                     String[] items = response.split(";");  
  99.                     String responseSourceid = items[0].substring(items[0].indexOf("=")+1);  
  100.                     String position = items[1].substring(items[1].indexOf("=")+1);  
  101.                     if(sourceid==null){//如果是第一次上传文件,在数据库中不存在该文件所绑定的资源id  
  102.                         service.save(responseSourceid, file);  
  103.                     }  
  104.                     RandomAccessFile fileOutStream = new RandomAccessFile(file, "r");  
  105.                     fileOutStream.seek(Integer.valueOf(position));  
  106.                     byte[] buffer = new byte[1024];  
  107.                     int len = -1;  
  108.                     int length = Integer.valueOf(position);  
  109.                     while( flag&&(len = fileOutStream.read(buffer)) != -1){  
  110.                         outStream.write(buffer, 0, len);  
  111.                         length += len;//累加已经上传的数据长度  
  112.                         Message msg = new Message();  
  113.                         msg.getData().putInt("length", length);  
  114.                         handler.sendMessage(msg);  
  115.                     }  
  116.                     if(length == file.length()) service.delete(file);  
  117.                     fileOutStream.close();  
  118.                     outStream.close();  
  119.                     inStream.close();  
  120.                     socket.close();  
  121.                 } catch (Exception e) {                      
  122.                     Toast.makeText(MainActivity.this, R.string.error, 1).show();  
  123.                 }  
  124.             }  
  125.         }).start();  
  126.     }  
  127. }  



另外别忘了添加下述权限哦!

<!-- 在SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 往SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 <!-- 访问internet权限 -->
<uses-permission android:name="android.permission.INTERNET"/>


ps;读者在原来的黎明活老师的代码基础上添加了停止按钮,是通过判断flag是否为false实现的!




本节相关代码下载:

1.soceke连接到服务端服务端发送的信息:点击下载

2.socket简易聊天室:点击下载

3.socket实现大文件的断点续传:点击下载

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值