【问题标题】:Sending files with sockets c# client/server使用套接字发送文件 c# 客户端/服务器
【发布时间】:2014-06-19 22:40:03
【问题描述】:

我正在尝试使用套接字发送文件..它不再使用几个字节的文件...如何解决这个问题? 这是一个客户端/服务器程序 我正在尝试发送至少 50 MB。

客户端-发送:

System.Net.Sockets.TcpClient tcpClient = new
    System.Net.Sockets.TcpClient();

tcpClient.Connect(recipientIP, FTPPORTNO);
int BufferSize = tcpClient.ReceiveBufferSize;
NetworkStream nws = tcpClient.GetStream();

FileStream fs;
fs = new FileStream(filename, FileMode.Open,
    FileAccess.Read);
byte[] bytesToSend = new byte[fs.Length];
int numBytesRead = fs.Read(bytesToSend, 0,
    bytesToSend.Length);
int totalBytes = 0;
for (int i = 0; i <= fs.Length/BufferSize; i++)
{
    //---send the file---
    if (fs.Length - (i*BufferSize) > BufferSize)
    {
        nws.Write(bytesToSend, i*BufferSize,
            BufferSize);
        totalBytes += BufferSize;
    }
    else
    {
        nws.Write(bytesToSend, i*BufferSize,
            (int) fs.Length - (i*BufferSize));
        totalBytes += (int) fs.Length - (i*BufferSize);
    }
    fs.Close();
}

接收代码:

try
{
    //---get the local IP address---
    System.Net.IPAddress localAdd =
        System.Net.IPAddress.Parse(
            ips.AddressList[0].ToString());
    //---start listening for incoming connection---
    System.Net.Sockets.TcpListener listener = new
        System.Net.Sockets.TcpListener(localAdd,
            FTPPORTNO);
    listener.Start();
    //---read incoming stream---
    TcpClient tcpClient = listener.AcceptTcpClient();
    NetworkStream nws = tcpClient.GetStream();
    //---delete the file if it exists---
    if (File.Exists("c:\\temp\\" + filename))
    {
        File.Delete("c:\\temp\\" + filename);
    }
    //---create the file---
    fs = new System.IO.FileStream("c:\\temp\\" + filename,
        FileMode.Append, FileAccess.Write);
    int counter = 0;
    int totalBytes = 0;
    do
    {
        //---read the incoming data---
        int bytesRead = nws.Read(data, 0,
            tcpClient.ReceiveBufferSize);
        totalBytes += bytesRead;
        fs.Write(data, 0, bytesRead);
        //---update the status label---
        ToolStripStatusLabel1.Text = "Receiving " +
                                        totalBytes + " bytes....";
        Application.DoEvents();
        counter += 1;
    } while (nws.DataAvailable);
    ToolStripStatusLabel1.Text = "Receiving " + totalBytes
                                    + " bytes....Done.";
    fs.Close();
    tcpClient.Close();
    listener.Stop();
}
catch (Exception ex)
{
    MessageBox.Show(ex.ToString());
}

服务器代码:

public void SendMessage (string message)
{
    //---adds a linefeed char---
    message += "\n";
    try
    {
        //---send the text---
        System.Net.Sockets.NetworkStream ns;
        lock (client.GetStream())
        {
            ns = client.GetStream();
            byte[] bytesToSend =
                System.Text.Encoding.ASCII.GetBytes(message);
            //---sends the text---
            ns.Write(bytesToSend, 0, bytesToSend.Length);
            ns.Flush();
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
}

有什么想法吗?

【问题讨论】:

  • 你尝试过异步吗? check this
  • 请编辑您的问题并格式化代码。你现在所拥有的几乎无法阅读。
  • 嗯……我应该把它分成块还是什么?
  • 我用空格格式化了你的代码(缩进)。下次你发布一些代码时,请确保它正确缩进。

标签: c# sockets


【解决方案1】:

您的主要问题是您期望DataAvailable == false 意味着没有更多数据即将到来。事实并非如此。 DataAvailable 表示数据是否现在可用。这并不意味着将来某个时候不会再有可用的了。

如果您要发送和接收任何类型的数据,发送者必须有某种方式告诉接收者消息的结尾在哪里。一般来说,有两种方法可以做到这一点:

  1. 发送一个标头,说明后面有多少字节。
  2. 在发送完所有其余数据后发送“消息结束”数据包。

对于文本协议,通常使用第二个选项:发送消息,并以换行符终止。这标志着消息的结束。

发送二进制数据时,通常使用第一种方法。该标头可以是简单的四个字节,表示文件的长度。所以在你的情况下,你会写这样的东西:

// tell receiver how many bytes are coming
byte[] lengthData = BitConverter.GetBytes[fs.Length];
nws.Write(lengthData, 0, lengthData.Length);
// then send the file

然后,接收者需要读取前四个字节,转换为整数,然后读取那么多字节。只有读取了那么多字节,才能知道已经到了文件的末尾。

// read length
byte[] lengthData = new byte[4];
bytesRead = nws.Read(lengthData, 0, 4);
// I assume here that it got all four bytes. In your code, you'll want to
// make sure that you got four bytes before moving on.
int bytesToRead = BitConverter.ToInt32(lengthData, 0);
// Now start your reading loop, and read until the total number of bytes read
// is equal to the bytesToRead value above.

【讨论】:

  • 有趣...很棒的一个!我试试看
【解决方案2】:

你为什么不在发件人端这样做:

fileStream.CopyTo(networkStream);

简单多了:)

在接收方,您不能假设DataAvailable = false 意味着没有更多数据。最好发送方在完成socket.Shutdown(SocketShutdown.Send) 后关闭连接,接收方继续读取直到返回0

发送方:

  1. 服务器发送文件
  2. 服务器调用socket.Shutdown(SocketShutdown.Send);
  3. 服务器执行socket.Receive(xxx) 以等待正常断开连接
  4. Socket.Close();

接收方:

  1. 从网络读取直到读取返回 0
  2. 关闭文件流(文件完成)
  3. 致电socket.Shutdown(SocketShutdown.Both)
  4. Socket.Close();

但是,您仍然有一个缺陷:套接字可能由于网络故障而断开连接。唯一知道的方法是先发送文件大小(在发送文件之前)

【讨论】:

    猜你喜欢
    • 2016-03-03
    • 2011-08-12
    • 2017-07-10
    • 1970-01-01
    • 2023-03-17
    • 2013-04-01
    • 2017-05-26
    • 2013-08-27
    • 1970-01-01
    相关资源
    最近更新 更多