当前位置: 代码迷 >> C# >> 【c#源码】安卓客户端经过TCP通信与Windows服务器进行文件传输
  详细解决方案

【c#源码】安卓客户端经过TCP通信与Windows服务器进行文件传输

热度:92   发布时间:2016-05-05 04:36:19.0
【c#源码】安卓客户端通过TCP通信与Windows服务器进行文件传输
APK文件  (对应的windows服务器端已经架设好,可以直接下载进行测试)

 源码       数据库文件

在前面一篇文章:【源码】c#编写的安卓客户端与Windows服务器程序进行网络通信 中我们探讨了,如何通过xamarin技术,完成安卓客户端与Windows服务器的通信,这篇文章,我们探讨一下使用场景非常多的文件传输.

先谈一下为什么使用xamarin.android技术吧,之前有开发过一个公文系统,c#语言开发,服务器部署在Windows Server 2003上,客户端采用Winform技术(.net2.0),使用了一段时间后,客户提出希望系统能够支持安卓移动端。首先想到了用java语言进行开发,用java写安卓程序应该是最好不过了,但是难点出现了,就是如何让java编写的安卓客户端与现有的Windows服务器上的程序通信,探索多日无果,于是想起了xamarin.adnroid技术,使用此技术,可以集成原有的C#通信框架,TCP通信这一块就解决了.这样做还有一个好处,即能够与原有的服务器端程序无缝集成,服务器端程序同时支持Windows客户端与安卓客户端。

学习Xamarin.Android的时间不长,水平有限,希望本文能够抛砖引玉,对xamarin开发有经验的朋友请多多指点,不足之处敬请批评指正。

本Demo效果图如下



当用户点击“从服务器获取文件”按钮后,服务器端会收到相应的请求,并开始通过TCP连接发送数据,本例中,服务器发送一张图片(大小为20k),客户端收到后,新建一个名称为"msdc"的文件夹,并把文件存储在此文件夹中。`

我们来看一下开发过程:

第一步:在Main.axml文件中,增加一个按钮
 <Button
        android:id="@+id/btnGetFile"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="从服务器获取文件" />

第二步:

客户端的MainActivity.cs文件中,编写该按钮相对应的方法
  Button buttonGetFile = FindViewById<Button>(Resource.Id.btnGetFile);

    buttonGetFile.Click += new EventHandler(buttonGetFile_Click);

void buttonGetFile_Click(object sender, EventArgs e)
        {
            GetFileFromServer();
        }

public void GetFileFromServer()
        { 
              //传递的参数为本地保存的路径
              string filePath = GetFileSavePath(this);

              //发送一个请求给服务器,服务器收到该请求后,开始发送文件
               newTcpConnection.SendObject ("GetFileFromServer", filePath);

                
        }

private String GetFileSavePath(Context context)
        {
            String filePath;
            if (checkSDCard())
            {
                filePath = Android.OS.Environment.GetExternalStoragePublicDirectory("").ToString() + @"/MSDC/";//File.Separator
            }
            else
            {
                filePath = context.CacheDir.AbsolutePath + @"/MSDC/";
            }
            Java.IO.File file = new Java.IO.File(filePath);
            if (!file.Exists())
            {
                Boolean b = file.Mkdirs();


            }
            else
            {

            }
            return filePath;
        }

GetFileSavePath

//检测是否存在SD卡
        private Boolean checkSDCard()
        {

            if (Android.OS.Environment.ExternalStorageState.Equals(Android.OS.Environment.MediaMounted))
            {
                return true;
            }
            else
            {
                return false;
            }

        }

checkSDCard 检查是否存在SD卡

第三步:看一下服务器端的处理程序
private void IncomingReqMobileUpFile(PacketHeader header, Connection connection, string filePath)
        {  
               //在此Demo中,我们直接指定一个文件,进行发送
                string filename = AppDomain.CurrentDomain.BaseDirectory + "Files\\" + "msdc.jpg";

                string fileID = FileIDCreator.GetNextFileID(NetworkComms.NetworkIdentifier.ToString());
                  
                SendFile sendFile = new SendFile(fileID, filename, filePath, connection, customOptions  );
                 
                sendFile.NowSendFile();
             
        }

using System;
using System.Collections.Generic;

using System.Text;

using NetworkCommsDotNet;
using System.ComponentModel;
using System.IO;

using NetworkCommsDotNet;
using DPSBase;
using Mobile.Entity ;
 using System.Threading ;

namespace MobileServer
{
    public class SendFile  
    {

      

        //取消文件的发送
        private volatile bool canceled = false;
        private FileTransFailReason fleTransFailReason = FileTransFailReason.Error ;
        /// <summary>
        /// The name of the file
        /// 文件名
        /// </summary>
        public string Filename { get; private set; }

        /// <summary>
        /// The connectionInfo corresponding with the source
        /// 连接信息
        /// </summary>
      

        /// <summary>
        /// 收发参数
        /// </summary>
        private SendReceiveOptions sendReceiveOptions;
        public SendReceiveOptions SendReceiveOptions
        {
            get { return sendReceiveOptions; }
            set { sendReceiveOptions = value; }
        }



        private Connection connection;

        public Connection Connection
        {
            get { return connection; }
            set { connection = value; }
        }

      

        //文件ID  用于管理文件 和文件的发送 取消发送相关

        private string fileID;

        public string FileID
        {
            get { return fileID; }
            set { fileID = value; }
        }
        //文件传输后存储的路径  客户端传过来的路径  再传回去 
        private string filePath;

        public string Filepath
        {
            get { return filePath; }
            set { filePath = value; }
        }



        /// <summary>
        /// The total size in bytes of the file
        /// 文件的字节大小
        /// </summary>
        public long SizeBytes { get; private set; }

        /// <summary>
        /// The total number of bytes received so far
        /// 目前收到的文件的带下
        /// </summary>
        public long SentBytes { get; private set; }

        /// <summary>
        /// Getter which returns the completion of this file, between 0 and 1
        ///已经完成的百分比
        /// </summary>
        public double CompletedPercent
        {
            get { return (double)SentBytes / SizeBytes; }

            //This set is required for the application to work
            set { throw new Exception("An attempt to modify read-only value."); }
        }

        /// <summary>
        /// A formatted string of the SourceInfo
        /// 源信息
        /// </summary>
      

        /// <summary>
        /// Returns true if the completed percent equals 1
        /// 是否完成
        /// </summary>
        public bool IsCompleted
        {
            get { return SentBytes == SizeBytes; }
        }

        /// <summary>
        /// Private object used to ensure thread safety
        /// </summary>
        object SyncRoot = new object();


        /// <summary>
        ///Event subscribed to by GUI for updates
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Create a new ReceivedFile
        /// </summary>
        /// <param name="filename">Filename associated with this file</param>
        /// <param name="sourceInfo">ConnectionInfo corresponding with the file source</param>
        /// <param name="sizeBytes">The total size in bytes of this file</param>
        public SendFile(string fileID, string filename, string filePath,  Connection connection, SendReceiveOptions sendReceiveOptions )
        {
            //文件ID
            this.fileID = fileID;
            this.Filename = filename;
            this.filePath = filePath;
           

            this.connection = connection;
            this.sendReceiveOptions = sendReceiveOptions;
           

        }

        public void NowSendFile()
        {
            new Action(this.StartSendFile).BeginInvoke(null, null);
        }


        public void StartSendFile()
        {
            try
            {
                //Create a fileStream from the selected file
                //根据选择的文件创建一个文件流
                FileStream stream = new FileStream(this.Filename, FileMode.Open, FileAccess.Read);

                //Wrap the fileStream in a threadSafeStream so that future operations are thread safe
                //包装成线程安全的数据流
                ThreadSafeStream safeStream = new ThreadSafeStream(stream);

                //Get the filename without the associated path information
                //获取不包含路径信息的文件名
                string shortFileName = System.IO.Path.GetFileName(Filename);

               
                long sendChunkSizeBytes = 4096;


                this.SizeBytes = stream.Length;

                long totalBytesSent = 0;
                do
                {
                    //Check the number of bytes to send as the last one may be smaller
                    long bytesToSend = (totalBytesSent + sendChunkSizeBytes < stream.Length ? sendChunkSizeBytes : stream.Length - totalBytesSent);

                    //Wrap the threadSafeStream in a StreamSendWrapper so that we can get NetworkComms.Net
                    //to only send part of the stream.
                    StreamSendWrapper streamWrapper = new StreamSendWrapper(safeStream, totalBytesSent, bytesToSend);

                    //We want to record the packetSequenceNumber
                    //我们希望记录包的顺序号
                    long packetSequenceNumber;
                    //Send the select data
                    connection.SendObject("PartialFileData", streamWrapper, sendReceiveOptions, out packetSequenceNumber);


                    //Send the associated SendInfo for this send so that the remote can correctly rebuild the data
                    //把包的顺序号记录在 SendInfo类中。
                    connection.SendObject("PartialFileDataInfo", new SendInfo(fileID, shortFileName, filePath, stream.Length, totalBytesSent, packetSequenceNumber), sendReceiveOptions);

                    totalBytesSent += bytesToSend;

                    //更新已经发送的字节的属性
                    SentBytes += bytesToSend;

                    ////Update the GUI with our send progress
                    //UpdateSendProgress((double)totalBytesSent * 100 / stream.Length);
                     
                
                    if (! this.canceled)
                    {
                        Thread.Sleep(30);
                    }

                } while ((totalBytesSent < stream.Length) && !this.canceled);

                 

                //AddLineToLog("Completed file send to '" + connection.ConnectionInfo.ToString() + "'.");
            }
            catch (CommunicationException)
            {
                

            }
            catch (Exception ex)
            {
                
            }
        }


         

    }
}

SendFile方法


------解决思路----------------------
有分的话就支持一下
------解决思路----------------------
有分的话就支持一下
------解决思路----------------------

------解决思路----------------------
支持
  相关解决方案