如何在复制数据之前在服务器端获取客户端文件名

本文关键字:服务器端 获取 客户端 文件名 复制 数据 | 更新日期: 2023-09-27 18:35:58

我的文件共享应用程序中没有想法了,我正在使用FileStream.copyto()从客户端接收服务器上的数据。它运行良好,但目前我已经为 var bytesread = fs.Read(buffer, 0, buffer.Length) 设置了 1024 的缓冲区大小,但我有两个问题:

  1. 我不确定缓冲区溢出之前它允许的最大大小。它应该是一种命中和试用方法吗?或者在 WLAN 上传输数据是否有固定的字节限制。

  2. 当我使用带有扩展名的硬编码文件名在服务器端检查代码时,就像在我预定义pathFileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)中一样,它可以工作,但是我将如何启用它以获取文件名。我的意思是,我应该使用一个固定协议,我应该为它分配一个预数据字节,然后在数据复制之前在服务器端检查和接收?

任何好主意。

如何在复制数据之前在服务器端获取客户端文件名

如果没有代码和更精确的描述,很难知道你在这里真正需要什么。但是,如果我理解正确,您会遇到这样一种情况:客户端终结点正在读取本地文件并将数据发送到服务器终结点,而服务器终结点正在使用 NetworkStream 对象进行 I/O。

假设是这种情况,那么客户端可以使用如下所示的内容包含文件名:

void TransmitFileName(Stream stream, string fileName)
{
    byte[] fileNameBytes = Encoding.UTF8.GetBytes(fileName),
        fileNameLengthBytes = BitConverter.GetBytes(fileNameBytes.Length);
    stream.Write(fileNameLengthBytes, 0, 4);
    stream.Write(fileNameBytes, 0, fileNameBytes.Length);
}

在服务器上,假设已将数据读入适当大小的byte[]缓冲区,则可以按如下方式解码信息:

string DecodeFileName(Stream stream)
{
    byte[] fileNameLengthBuffer = new byte[4];
    FillBufferFromStream(stream, fileNameLengthBuffer);
    int fileNameLength = BitConverter.ToInt32(fileNameLengthBuffer, 0);
    byte[] fileNameBuffer = new byte[fileNameLength];
    FillBufferFromStream(stream, fileNameBuffer);
    return Encoding.UTF8.GetString(fileNameBuffer);
}
void FillBufferFromStream(Stream stream, byte[] buffer)
{
    int cbTotal = 0;
    while (cbTotal < buffer.Length)
    {
        int cbRead = stream.Read(buffer, cbTotal, buffer.Length - cbTotal);
        if (cbRead == 0)
        {
            throw new InvalidDataException("premature end-of-stream");
        }
        cbTotal += cbRead;
    }
}

我将实际的服务器端 I/O 留给读者进行练习。但是,请注意,使用 TCP,不能保证任何给定的读取操作都会阻塞,直到您请求的所有字节都被读取。因此,您需要连续读取,直到获得解码操作成功所需的所有字节。

<编辑>>我添加了必要的逻辑来从NetworkStream对象读取数据。请注意,我包含一个帮助程序方法,该方法将检查实际读取的字节数,并继续读取字节数,填充缓冲区,直到实际读取所需的字节数。在实际读取所需的所有字节之前,您不能指望Read()方法来阻止。/p> >

在实践中,这可能意味着分两部分进行解码:第一部分获取fileNameLength值(您知道需要 4 个字节),第二部分获取文件名(只有在解码fileNameLength值后您才会知道其长度)。

在文件名的字节之后,您可以像以前一样传输文件数据本身。


编辑:要在您发布的代码上下文中使用上述内容...

客户端:在发送实际文件数据之前调用 TransmitFileName() 方法。 例如:

using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
    TransmitFileName(netstream, Path.GetFileName(path));
    ...

服务器:在接收实际文件数据之前调用DecodeFileName()方法。 例如:

//open a stream to get data 
NetworkStream netStream = client.GetStream(); 
//Directory to save
string DirName = @"D:'NewFolder'Test'";
//File Name is requirement here to save data at.
string fileloc = Path.Combine(DirName, DecodeFileName(netStream));
MessageBox.Show(fileloc);