0

見つけたすべての解決策を試しましたが、何もうまくいかないようです。テキスト ファイル以外はすべて破損します。TCP は 8KB を超えて送信できないと誰かが言ったので、私は問題を解決しようとしましたが、解決したと思います。今、テキストファイルを送信すると(サイズに関係なく)、完全に届きますが、それ以外は破損します。カットのコードがパフォーマンスに負担がかかることはわかっていますが、それについては後で考えます。

これが私の送信者コードです:

private string SendFile(string tosend, string tosendname)
{
    ipadd = IPAddress.Parse(textBox2.Text);
    ep = new IPEndPoint(ipadd, 6112);
    Sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
    Sender.Connect(ep);
    Thread.Sleep(100);
    byte[] filetosend = System.IO.File.ReadAllBytes(tosend);
    FileStream fs = new FileStream(tosend, FileMode.Open, FileAccess.Read);
    //Read byte from image
    fs.Read(filetosend, 0, filetosend.Length);
    fs.Flush();
    fs.Close();
    int countt = filetosend.Count();
    int dividedcount = countt / 7000;
    Sender.Send(Encoding.ASCII.GetBytes("filesize#" + filetosend.Count().ToString()));
    Thread.Sleep(500);
    List<byte> cuttedtosend = new List<byte>();
    for (int counti = 0; counti < dividedcount; counti++)
    {
        cuttedtosend = new List<byte>();
        for (int index = 0; index < 7000; index++)
        {
            cuttedtosend.Add(filetosend[(filetosend.Count() - countt) + index]);
        }
        Sender.Send(cuttedtosend.ToArray());
        Thread.Sleep(100);
        countt -= 7000;
        richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText("Countt = " + countt + "\n"); });
        richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText("Counti = " + counti + "\n"); });
    }
    richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText("Done"); });
    cuttedtosend = new List<byte>();
    for (int index = filetosend.Count() - countt; index < filetosend.Count(); index++)
    {
        //richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText(index + "this is 2 \n"); });
        cuttedtosend.Add(filetosend[index]);
    }
    Sender.Send(cuttedtosend.ToArray());
    countt -= countt;
    return "";
}

そして、ここに私の受信コードがあります:

private async void StartReceiving()
{
    List<byte> neededbytes = new List<byte>();
    receivedbyte = new byte[InputForm.s];
    Receiver.Bind(new IPEndPoint(IPAddress.Parse("0"), 6112));
    Receiver.Listen(1000);
    string filename = "Downloadedfile";
    bool cont = false;
    while (true)
    {
        Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
        Client = Receiver.Accept();
        int filesize = 0;
        byte[] receivechecker = new byte[100];
        Client.Receive(receivechecker);
        if(Encoding.ASCII.GetString(receivechecker).Contains("filesize#"))
        {
            filesize = Convert.ToInt32(Encoding.ASCII.GetString(receivechecker).Remove(0, 9));
            Client.Receive(receivechecker);
        }
        if (Encoding.ASCII.GetString(receivechecker).Contains("#100254#"))
        {
            string[] splttedtext = Encoding.ASCII.GetString(receivechecker.ToArray()).Split('#');
            if (splttedtext[0] == "mess")
            {
                MessageBox.Show(splttedtext[2]);
            }
            else if (splttedtext[0] == "filename")
            {
                //MessageBox.Show(splttedtext[2]);
                filename = splttedtext[2];
                //filename.Replace(@"\", @"/");
                cont = true;
            }
        }
        else
        {
            List<byte> tosave = new List<byte>();
            richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText(filesize.ToString() + "\n"); });
            int countt = filesize / 7000;
            FileStream writer = File.Create("DownloadedFile.jpg");
            for (int counti = 0; counti < countt; counti++)
            {
                byte[] toadd = new byte[7000];
                richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText("Counti = " + counti.ToString() + "\n"); });
                Client.Receive(toadd);
                writer.Write(toadd,0,toadd.Count());
                neededbytes.AddRange(toadd);
                filesize -= 7000;
            }
            richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText(filesize.ToString() + "\n"); });
            byte[] toadds = new byte[filesize];
            Client.Receive(toadds);
            writer.Write(toadds,0,toadds.Count());
            writer.Close();
            neededbytes.AddRange(toadds);
            filesize -= filesize;
        }
   }

前もって感謝します:D

編集:7MBのテキストファイルを送信しようとしたところ、完了しました........

4

2 に答える 2

3

最も差し迫った問題は、必ずしも受信したとは限らないバイトを保存していることです。たとえば、次のようなものがあります。

        for (int counti = 0; counti < countt; counti++)
        {
            byte[] toadd = new byte[7000];
            richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText("Counti = " + counti.ToString() + "\n"); });
            Client.Receive(toadd);
            writer.Write(toadd,0,toadd.Count());
            neededbytes.AddRange(toadd);
            filesize -= 7000;
        }

のドキュメントには、メソッドは要求したバイト数までReceive受け取ると書かれています。特にファイルの最後で、要求したよりも少ないバイト数を返すことは珍しくありません (ファイルの長さを超えて受け取ることができないため)。

あなたは書く必要があります:

var bytesRead = Client.Receive(toadd);
writer.Write(toadd, 0, bytesRead);  // only write as many bytes as you've read

一般に、コードは非常に複雑であり、他にもいくつかの問題が発生する可能性があります。たとえば、ファイル サイズを送信するコードは 500 ミリ秒スリープしますが、これは受信側が送信されたバイト数を読み取るのにちょうど十分な時間です。そのスリープがなければ、コードは失敗します。

ファイル名を受け取るコードはありますが、送信するコードはありません。

ASCII タグを削除して、バイナリで送信することをお勧めします。以下は、書き換えられた Send メソッドです。

private string SendFile(string tosend, string tosendname)
{
    ipadd = IPAddress.Parse(textBox2.Text);
    ep = new IPEndPoint(ipadd, 6112);
    Sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
    Sender.Connect(ep);

    byte[] filetosend = System.IO.File.ReadAllBytes(tosend);
    byte[] filesizeBytes = BitConverter.GetBytes(filetosend.Length);
    Sender.Send(filesizeBytes); // sends the length as an integer

    // note: You could use Socket.Send(filetosend) here.
    // but I'll show an example of sending in chunks.
    int totalBytesSent = 0;
    while (totalBytesSent < filetosend.Length)
    {
        int bytesLeft = filetosend.Length - totalBytesSent;
        int bytesToSend = Math.Min(bytesLeft, 7000);
        Sender.Send(filetosend, totalBytesSent, bytesToSend);
        richTextBox1.Invoke((MethodInvoker)delegate 
            { richTextBox1.Append(totalBytesSent + " bytes sent\n"); });
        totalBytesSent += bytesToSend;
    }
    richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText("Done"); });
    return "";
}

受信側のコードも同様に簡略化されています。

private async void StartReceiving()
{
    Receiver.Bind(new IPEndPoint(IPAddress.Parse("0"), 6112));
    Receiver.Listen(1000);
    string filename = "Downloadedfile";
    bool cont = false;
    while (true)
    {
        Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
        Client = Receiver.Accept();

        // read the length
        byte[] filesizeBytes = new byte[4];
        int totalBytesReceived = 0;
        while (totalBytesReceived < 4)
        {
            int bytesRead = Client.Receive(
                filesizeBytes, totalBytesReceived, 4-totalBytesReceived);
            totalBytesReceived += bytesRead;
        }
        int filesize = BitConverter.ToInt32(filesizeBytes);
        richTextBox1.Invoke((MethodInvoker)delegate 
            { richTextBox1.AppendText(filesize.ToString() + "\n"); });

        // now read the file
        using (FileStream writer = File.Create("DownloadedFile.jpg"))
        {
            byte[] readBuffer = new byte[7000];
            totalBytesReceived = 0;
            while (totalBytesReceived < filesize)
            {
                int bytesToRead = Math.Min(7000, filesize - totalBytesReceived);
                int bytesRead = Client.Receive(readBuffer, 0, bytesToRead);
                totalBytesRead += bytesRead;
                writer.Write(readBuffer, 0, bytesRead);
                richTextBox1.Invoke((MethodInvoker)delegate 
                    { richTextBox1.AppendText("Read " + bytesRead.ToString() + "bytes\n"); });
            }
            richTextBox1.Invoke((MethodInvoker)delegate 
                { richTextBox1.AppendText("Done. " + totalBytesRead.ToString() + " bytes\n"); });
        }
   }

ファイル名を送信する場合は、ファイル名を UTF8 ( Encoding.UTF8.GetBytes(filename)) に変換してから、ファイルの長さを表す int (4 バイト) を送信し、次にバッファーを送信することをお勧めします。それを受け取るには、ファイル サイズの読み取り方法を示したように 4 バイトのファイル名の長さを読み取り、次にファイル名のそのバイト数を読み取り、文字列 ( Encoding.UTF8.GetString(bytes, 0, filenameLength)) に変換します。

コードのタイプミスや軽微なエラーはご容赦ください。私は記憶からこれを行っており、あなたのコーディング スタイルをある程度維持しようとしています。

于 2013-09-04T18:33:59.717 に答える
1

送信したのと同じブロックが受信されることを期待していると思います。つまり、レコードの境界が保持されます。そうではありません。TCP は、送信されたすべてのバイトが受信され、その順序が保持されることを保証します。しかし、大きな 10k の送受信を 1 回実行し、10k の 1 バイト メッセージを受信することはできます。

于 2013-09-04T18:39:54.070 に答える