문제

TCPCLIENT 및 TCPLISTERE를 사용하여 네트워크를 통해 MP3 파일을 보내고 싶습니다. 소켓을 사용 하여이 솔루션을 구현했지만 몇 가지 문제가 있었으므로 파일을 보내는 새로운/더 나은 방법을 조사하고 있습니다.

다음과 같이 보이는 바이트 배열을 만듭니다 : longth_of_filename | filename | 파일

그런 다음 위에서 언급 한 클래스를 사용하여 전송해야하지만 서버 측에서 읽은 바이트 배열은 완전히 엉망이되어 이유가 확실하지 않습니다.

내가 보내는 데 사용하는 방법 :

 public static void Send(String filePath)
    {
        try
        {
            IPEndPoint endPoint = new IPEndPoint(Settings.IpAddress, Settings.Port + 1);
            Byte[] fileData = File.ReadAllBytes(filePath);
            FileInfo fi = new FileInfo(filePath);

            List<byte> dataToSend = new List<byte>();
            dataToSend.AddRange(BitConverter.GetBytes(Encoding.Unicode.GetByteCount(fi.Name))); // length of filename
            dataToSend.AddRange(Encoding.Unicode.GetBytes(fi.Name)); // filename
            dataToSend.AddRange(fileData); // file binary data


            using (TcpClient client = new TcpClient())
            {
                client.Connect(Settings.IpAddress, Settings.Port + 1);

                // Get a client stream for reading and writing.
                using (NetworkStream stream = client.GetStream())
                {
                    // server is ready 
                    stream.Write(dataToSend.ToArray(), 0, dataToSend.ToArray().Length);
                }
            }

        }
        catch (ArgumentNullException e)
        {
            Debug.WriteLine(e);
        }
        catch (SocketException e)
        {
            Debug.WriteLine(e);
        }
    }
}

그런 다음 서버 측에서 다음과 같이 보입니다.

    private void Listen()
    {
        TcpListener server = null;
        try
        {
            // Setup the TcpListener
            Int32 port = Settings.Port + 1;
            IPAddress localAddr = IPAddress.Parse("127.0.0.1");

            // TcpListener server = new TcpListener(port);
            server = new TcpListener(localAddr, port);

            // Start listening for client requests.
            server.Start();

            // Buffer for reading data
            Byte[] bytes = new Byte[1024];
            List<byte> data;

            // Enter the listening loop.
            while (true)
            {
                Debug.WriteLine("Waiting for a connection... ");
                string filePath = string.Empty;

                // Perform a blocking call to accept requests.
                // You could also user server.AcceptSocket() here.
                using (TcpClient client = server.AcceptTcpClient())
                {
                    Debug.WriteLine("Connected to client!");
                    data = new List<byte>();

                    // Get a stream object for reading and writing
                    using (NetworkStream stream = client.GetStream())
                    {
                        // Loop to receive all the data sent by the client.
                        while ((stream.Read(bytes, 0, bytes.Length)) != 0)
                        {
                            data.AddRange(bytes);
                        }
                    }
                }

                int fileNameLength = BitConverter.ToInt32(data.ToArray(), 0);
                filePath = Encoding.Unicode.GetString(data.ToArray(), 4, fileNameLength);
                var binary = data.GetRange(4 + fileNameLength, data.Count - 4 - fileNameLength);

                Debug.WriteLine("File successfully downloaded!");

                // write it to disk
                using (BinaryWriter writer = new BinaryWriter(File.Open(filePath, FileMode.Append)))
                {
                    writer.Write(binary.ToArray(), 0, binary.Count);
                }
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex);
        }
        finally
        {
            // Stop listening for new clients.
            server.Stop();
        }
    }

누구든지 내가 놓치거나 잘못하고있는 것을 볼 수 있습니까?

도움이 되었습니까?

해결책

부패는 서버의 다음 코드로 인해 발생합니다.

// Loop to receive all the data sent by the client.
while ((stream.Read(bytes, 0, bytes.Length)) != 0)
{
    data.AddRange(bytes);
}

stream.Read 항상 채우는 것은 아닙니다 bytes 완충기. TCP 소켓에 더 이상 데이터를 사용할 수 없거나 메시지의 마지막 덩어리를 읽을 때 (정확한 버퍼 크기의 정확한 배수가 아닌 한) 채워지지 않습니다.

그만큼 data.AddRange 전화는 모든 것을 추가합니다 bytes (항상 가득 차 있다고 가정합니다). 결과적으로 이것은 때때로 이전 호출에서 데이터를 추가하게됩니다. stream.Read. 이를 수정하려면 반환 된 바이트 수를 저장해야합니다. Read 이 바이트 수를 추가하십시오.

int length;

while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
{
    var copy = new byte[length];
    Array.Copy(bytes, 0, copy, 0, length);
    data.AddRange(copy);
}

성능 및 메모리 사용량을 개선하기 위해 코드를 재구성 할 수 있습니다 (결과적으로 읽기 쉽게 읽을 수 있음). 전송하기 전에 클라이언트의 메모리에 모든 데이터를 읽는 대신 NetworkStream. 서버에서 스트림에서 메모리로 모든 것을 복사 할 필요는 없습니다. 4 바이트 파일 이름 길이를 읽고 해독 한 다음 파일 이름을 읽고 디코딩하고 마지막으로 스트림의 나머지 부분을 직접 복사 할 수 있습니다. FileStream (그만큼 BinaryWriter 불필요).

또한 출력 파일을 FileMode.Append. 즉, 전송 된 각 파일이 동일한 이름의 이전 사본에 추가됩니다. 사용하고 싶을 수도 있습니다 FileMode.Create 대신 파일이 이미 존재하는 경우 덮어 씁니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top