【问题标题】:C# tcp socket client server transfer multiple files problemC# tcp socket客户端服务器传输多个文件问题
【发布时间】:2010-12-08 18:08:53
【问题描述】:

我有 2 个应用程序,一个是服务器应用程序,另一个是客户端应用程序。两者都在同一台计算机上。客户端有一个按钮。单击此按钮时,客户端开始从服务器下载文件。 问题是,有时客户端成功接收到所有文件,但有时客户端只接收到第一个文件然后停止传输。下面的代码有问题吗?任何人都可以告诉我我哪里错了吗?我只是这样编码的新手。 非常感谢您的帮助。提前致谢。 代码如下:

当用户点击客户端上的按钮时,客户端会向服务器发送一个下载文件的请求:

//client side
sendRequest("requestFiles ");

服务器收到令牌请求文件后会准备文件供客户端下载

// server side
if (execmd == "requestFiles")
{
    string[] fList = Directory.GetFiles(folderDir);
    for (int i = 0; i < fList.Length; i++)
    {
        FileInfo fi = new FileInfo(fList[i]);
        string[] mDesc = new string[3];
        mDesc[0] = fi.Name;
        mDesc[1] = fi.Length.ToString();
        mDesc[2] = fi.FullName;
        string fileSend = "CommitRequest " + fi.Name + " " + fi.Length.ToString() + " " + usID + " " + mName;
        sendRequest(fileSend);
        ClientDownloadingFromServer(mDesc[2], mDesc[1], sock);
    }
    sendComment("AllUpDone");
    continue;
}

对于每个需要上传的文件,服务器将发送一个带有文件详细信息(名称、大小)的令牌 CommitRequest 当客户端收到 CommitRequest:

//client side
if (execmd == "CommitRequest")
{
    //get file name and file size
    downloadFileFromServer(sock);
    continue;
}

客户端的方法downloadFileFromServer:

//client side
private void downloadMapFromServer(Socket s)
{        
    Socket sock = s;
    //prepare directory rootDir to store file
    System.IO.FileStream fout = new System.IO.FileStream(rootDir + "\\" + fileN, FileMode.Create, FileAccess.Write);
    NetworkStream nfs = new NetworkStream(sock);
    long size = int.Parse(fileS);
    long rby = 0;
    try
    {
        //loop till the Full bytes have been read
        while (rby < size)
        {
            byte[] buffer = new byte[1024];
            //Read from the Network Stream
            int i = nfs.Read(buffer, 0, buffer.Length);
            fout.Write(buffer, 0, (int)i);
            rby = rby + i;
        }
        fout.Close();
    }
    catch (Exception ed)
    {
        Console.WriteLine("A Exception occured in file transfer" + ed.ToString());
        MessageBox.Show(ed.Message);
    }
}

服务端方法clientDownloadFromServer:

//server side
void ClientDownloadingFromServer(string fiPath, string fiSize, Socket s)
{
    string parm1 = fiPath;
    string parm2 = fiSize;
    try
    {
        FileInfo ftemp = new FileInfo(parm1);
        long total=ftemp.Length;
        long rdby=0 ;
        int len=0 ;
        byte[] buffed = new byte[1024] ;
        // Open the file requested for download 
        System.IO.FileStream fin = new System.IO.FileStream(parm1,FileMode.Open , FileAccess.Read) ;

        NetworkStream nfs = new NetworkStream(sock) ;

        while(rdby < total && nfs.CanWrite)
        {
             //Read from the File (len contains the number of bytes read)
             len =fin.Read(buffed,0,buffed.Length) ;
             //Write the Bytes on the Socket
             nfs.Write(buffed, 0,len);
             //Increase the bytes Read counter
             rdby=rdby+len ;    
        }
        fin.Close();
    }
}

【问题讨论】:

  • 您是说有时您只收到 1 个 CommitRequest,还是您收到多个 CommitRequest 但只下载一个文件?
  • CommitRequest 的目的是发送文件名和文件大小,让客户端准备从服务器接收文件,同时让客户端调用下载方法。而且我不知道如何检查它。调试对我不起作用。我的问题例如,服务器发送2个文件,abc.txt和def.txt,但客户端只收到abc.txt,而且这个文件的大小比服务器上的abc.txt大(1kb)。

标签: c# sockets tcp file-transfer


【解决方案1】:

问题与将接收字节视为文件字节或令牌字节有关。您的客户端代码正在尝试读取等于缓冲区大小的字节。服务器一个接一个地发送“CommitRequest”令牌和文件字节。因此,假设第一个文件大小为 1200 字节。服务器将发送这 1200 个字节,然后是第二个文件的“CommitRequest”,然后是第二个文件字节。现在,客户端将读取第一个文件的 1024 字节。然后它将读取接下来的 1024 个字节 - 但这些字节将包含第一个文件的剩余 176 个字节,来自服务器的“CommitRequest”响应,然后是第二个文件的前几个字节。您的客户端代码只占用前 176 个字节,并忽略下一个包含下一个文件数据的字节。

您可以通过两种方式解决此问题 - 确保剩余字节得到处理(这可能很棘手,因为剩余字节可能部分有“CommitRequest”响应)或重新构建您的解决方案,以便每次文件传输都会仅在客户端请求后启动。

【讨论】:

  • 感谢 VinayC 的回答。我想我明白你的意思了。我忘了提到问题也发生在同一组文件中。例如,服务器发送 3 个文件 file1、file2、file3。有时客户端获取所有 3 个文件,但有时客户端仅获取文件 1。
  • 如果我这样改变它,你认为它会起作用吗?客户端点击下载,服务器发送一个包含所有文件名和文件大小的字符串。客户端 foreach 字符串中的文件名,发送带有文件名的请求令牌并调用方法下载(上面的 downloadMapFromServer)。服务器接收令牌请求和文件名,然后使用该文件名搜索文件,然后将文件发送到客户端(ClientDownloadFromServer)。所以我从服务器更改了 for 命令给客户。这会很困难,因为我必须从字符串中获取文件名和大小。你对此有何看法?它会修复错误吗?它有效吗?再次感谢您的 4 次帮助。
  • @PeteMerry,IMO,逐个请求每个文件的方法听起来不错,而且很简单。文件名和大小可以由您在文件名中不太可能找到的一些标记序列(例如 ||)分隔(简单的字符串。Split 会为您提供文件列表)。
  • 感谢 VinayC。现在我将尝试实现它。但是,为什么使用相同的文件集,有时代码有效但有时无效?下载和上传代码有什么问题吗?此外,如果我尝试多次下载程序停止工作。例如第 1 次下载 file1、file2、第 2 次下载 fileA、fileB、3... 第 4 次程序停止,没有崩溃但停止了。
  • @PeteMerry,代码就是这样,很难预测它什么时候可以工作,什么时候不能工作。这是因为服务器代码试图一个接一个地传输文件。在客户端,它可以以任意数量的字节集接收。例如,第一个文件可以设置为 1,第二个文件可以设置为 2 等或第一个文件的一部分作为设置 1,其余文件 + 第二个文件的一部分作为设置 2 以及许多这样的组合。
猜你喜欢
  • 2020-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-29
  • 2012-07-04
  • 1970-01-01
  • 2017-08-29
相关资源
最近更新 更多