Android 客户端:

1. 创建Socket对象

Socket socket = new Socket();


2.创建连接到指定的主机、端口

socket.connect(new InetSocketAddress("10.10.10.100", 980));


3.创建File对像,并指定要传输的文件绝对路径

File f=new File("/sdcard2/AppManage.apk");


如果需要用断点继传需要用这个RandomAccessFile对象

//RandomAccessFile fileOutStream = new RandomAccessFile(f, "r");
//"r":以只读文方式打开指定文件。如果你写的话会有IOException。
//"rw":以读写方式打开指定文件,不存在就创建新文件。


4.将文件绑定到InputStream流对象

InputStream fileOutStream = new FileInputStream(f);


5.创建OutputStream对象

OutputStream outputStream = socket.getOutputStream();


如果需要用断点继传需在这里设定跳过的字节。

//fileOutStream.seek(sek);


6.获取文件总长度

long count = fileOutStream.available();

上面可能读不到文件的总长度,因为读取时需要时间,如果SD卡质量不好可能要等待一会。

所以最好加上这一句

while(count == 0){
        count = fileOutStream.available();
  }

如果是用断点继传用这个获取文件总长度

long count = fileOutStream.length();


7. 将文件总字节数写入到流中,这里要做一个long转成8个字节的转换

byte[] totalCount = new byte[8]; //将总数转为byte字符
outputStream.write(totalCount);

 

8. 指定每包大小字节和计算包数   -2,147,483,648 到  2,147,483,647

int PacketSize = 10240;//这里指定每包为10Kbyte

int PacketCount = (int)(count / ((long)PacketSize));//总包数

int LastDataPacket = (int)(count - ((long)(PacketSize * PacketCount)));//余字节数,也可能会是0


9.循环将包写入到流中

byte[] buffer = new byte[PacketSize];//设定缓冲区
 for(int i=0; i<PacketCount; i++){     fileOutStream.read(buffer,0,buffer.length);//将文件读到缓冲区
       byte[] bufferLength = new byte[4]//需要将buffer的长度转换为byte字节
       outputStream.write(bufferLength);//写入4个字节代表buffer的长度
       outputStream.write(buffer);//将缓冲写入到流}


10.写入余字节数

if(LastDataPacket != 0){
       buffer = new byte[LastDataPacket];//重新设定缓冲区大小
       fileOutStream.read(buffer,0,buffer.length);将文件读到缓冲区
       byte[] bufferLength = new byte[4]//需要将buffer的长度转换为byte字节
       outputStream.write(bufferLength);//写入4个字节代表buffer的长度
       outputStream.write(buffer);//将缓冲写入到流
 }


11. 最后关闭和刷新



outputStream.flush();

fileOutStream.close();
outputStream.close();

需要注意的是,如果未按7章中写入文件总字节到流中服务器就不会知道文件的大小,导致只能一直接收并写入到文件中,并且

需要客户端关闭时才会停止,没办法回复信息。

 

服务器端(用C#写的服务器端),主要解释将流写入到文件

1.创建文件对象FileStream

FileStream MyFileStream = new FileStream("保存路径", FileMode.Create, FileAccess.Write);
如果是断点继传,需要用下面的方式

FileStream MyFileStream = new FileStream("保存路径", FileMode.Append, FileAccess.Write);
MyFileStream.Seek(0, SeekOrigin.Begin);


2.读取文件总字节

byte[] total = new byte[8];//创建缓冲区
Receive(total, 0, 8, SocketFlags.None);//读到8个字节位置

long totalCoun = BitConverter.ToInt64(total, 0);//转换成long


3.循环读取流并写入到文件

while (true) {
         //循环读取,每次读到包指定位置
         byte[] data = ReceiveVarData(client);
          if (data.Length == 0) {
              break;//读取0时退出
           } else {              //写入到文件中
               MyFileStream.Write(data, 0, data.Length);
           }
 }//关闭
 MyFileStream.Close();


最后是ReceiveVarData的方法,也是关键部份

public byte[] ReceiveVarData(Socket s){
             int total = 0;
             int recv;
             byte[] datasize = new byte[4];//创建缓冲区
             recv = s.Receive(datasize, 0, 4, SocketFlags.None);//读到4个字节位置
             int size = BitConverter.ToInt32(datasize, 0);//转换为int            int dataleft = size;
             byte[] data = new byte[size];//创建当前要接收的大小缓冲区           因为网络可能会堵塞,这里也要做循环判断。
             while (total < size) {
                 recv = s.Receive(data, total, dataleft, SocketFlags.None);//开始读取
                 if (recv == 0) {
                     data = null;
                     break;
                 }
                 total += recv;
                 dataleft -= recv;
             }
             return data;
 }