使用 TCP 文件传输客户端发送时出现问题

Trouble with sending using TCP File Transfer Client

我必须开发一个简单的 TCP 文件传输客户端作为 exercise/demonstration 的一部分,但我在数据传输方面遇到了问题。

我已经获得了 TCP 文件服务器,它将接收传入的文件,我必须编写一个客户端,该客户端将连接到服务器并将文件发送到服务器。到目前为止,我已经成功地将所选文件的数据转换为可以传输并成功打开连接然后发送数据的格式,但是甚至在接收服务器上遇到问题 - 我不允许更改服务器的代码,因此应该以服务器可以解释发送的数据的方式更改我的客户端代码。这是我使用的代码(有些被遗漏了,这是简单的开销,比如获取 IP 地址的输入框等):

Link 用于 TCP 服务器 VS 解决方案(如果您愿意):https://www.mediafire.com/?682owf9wtdzmxac

TCP 文件传输客户端发送方法:

    private void TransferFile(string _sFileName, string _sIPAdress)
    {
        //Convert data for transfer
        Stream strmfilestream = File.OpenRead(_sFileName);
        Byte[] bFileBuffer = new Byte[strmfilestream.Length];

        //Open TCP/IP Connection
        TcpClient tcpClientSocket = new TcpClient(_sIPAdress,8080);
        NetworkStream nsNetworkStream = tcpClientSocket.GetStream();
        nsNetworkStream.Write(bFileBuffer,0,bFileBuffer.GetLength(0));
        nsNetworkStream.Close();
    }

*注意:_sFileName 只是完整的文件路径 + 来自 OpenFileDialog 的文件名。

这是服务器的加载方法,可以让事情顺利进行:

        if (!Directory.Exists(@"C:\TCPFileServer"))
            Directory.CreateDirectory(@"C:\TCPFileServer");

        //Get Ip address of server host machine
        IPHostEntry IPHost = Dns.GetHostEntry(Dns.GetHostName());            
        lblServerIP.Text = IPHost.AddressList[5].ToString();
        lstSockets = new ArrayList();
        Thread thdListener = new Thread(new ThreadStart(listenerThread));
        thdListener.IsBackground = true; //This will enabe the thread to terminate when application is closed
        thdListener.Start();

这里是监听线程方法:

    public void listenerThread()
    {
        TcpListener tcpListener = new TcpListener(IPAddress.Any, 8080);
        tcpListener.Start();
        while (true)
        {
            Socket handlerSocket = tcpListener.AcceptSocket();
            if (handlerSocket.Connected)
            {
               this.Invoke((Action)(() => lstConnections.Items.Add(handlerSocket.RemoteEndPoint.ToString() + " connected.")));
                lock (this) 
                {
                    lstSockets.Add(handlerSocket);
                }
                ThreadStart thdsHandler = new ThreadStart(handlerThread);
                Thread thdHandler = new Thread(thdsHandler);
                thdHandler.Start();
            }
        }
    }

最后是处理线程方法:

    public void handlerThread()
    {
        try
        {
            int iBlockSize = 1024 * 3000; //3mb block size
            Byte[] dataByte = new Byte[iBlockSize];
            Byte[] rcvdData = new Byte[128000 * 1024];//128mb File Limit
            Socket handlerSocket = (Socket)lstSockets[lstSockets.Count - 1];
            NetworkStream networkStream = new NetworkStream(handlerSocket);

            int i = 0;

            int iRcvdBytes = 0;

            while (true)
            {
                //Read from socket and store to buffer 'dataByte'
                iRcvdBytes = networkStream.Read(dataByte, 0, iBlockSize);
                dataByte.CopyTo(rcvdData, i);//Copy recieved bytes,from buffer, to another byte array
                i += iRcvdBytes;
                if (iRcvdBytes == 0) break;
            }

            //Get the File name length, BitConvertor occupies the first 4 bytes
            int iFileNameLength = BitConverter.ToInt32(rcvdData, 0);

            //Get the file name using length as the size and 4 as the offset
            string sFileName = Encoding.ASCII.GetString(rcvdData, 4, iFileNameLength);

            Stream fileStream = File.Open("C:\TCPFileServer\" + sFileName, FileMode.Create);

            //Populate raw File on local machine
            fileStream.Write(rcvdData, 4 + iFileNameLength, i - 4 - iFileNameLength);

            fileStream.Close();

            //Update BRS Net Files Server Log
            this.Invoke((Action)(() => lstConnections.Items.Add(sFileName + ": Transfered.")));

            //Close Connection
            networkStream.Close();
            handlerSocket = null; //Clear socket
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);   
        }
    }

现在我已经调试了,据我所知,我第一次看到问题是当我们试图确定代码读取的文件名长度时 int iFileNameLength = BitConverter.ToInt32(rcvdData, 0); - 当调试这个变量时始终确定为“0”,我认为这是不正确的?我不知道。需要达到的要求结果是Server应该接收到文件,并且传输成功后,ListBox中应该显示文件名。

以下是显示我遇到的问题的屏幕截图:

我们可以看到确实收到了字节:

请注意,无法使用文件名长度和偏移量检索文件名:

因此,出现以下错误:

我的经验和专业知识在别处,这是我第一次在这种范式(通过网络传输文件)中编码。然而,我确实有 about/studied OSI 模型和 TCP/IP 协议栈的理论知识,但从未编写过这样的代码。给我的一个注意事项是,服务器的编码假定它将在特定 PC 上执行,如果绝对必要,我可以更改服务器应用程序的代码。

服务器代码有两点您应该注意

/Get the File name length, BitConvertor occupies the first 4 bytes
                int iFileNameLength = BitConverter.ToInt32(rcvdData, 0);

                //Get the file name using length as the size and 4 as the offset
                string sFileName = Encoding.ASCII.GetString(rcvdData, 4, iFileNameLength);​

1) 您需要在上传开始时添加一个字节数。 2) 代码使用Ascii 编码,这意味着您不能上传二进制数据。

试试这个。您必须在客户端执行相反的操作,使用 List 会使事情变得更容易。

private void TransferFile(string _sFileName, string _sIPAdress)
        {
            List<Byte> bFileBuffer = File.ReadAllBytes(_sFileName).ToList();


            byte[] bFileName = Encoding.ASCII.GetBytes(_sFileName);
            bFileBuffer.InsertRange(0, bFileName);

            //Get the File name length, BitConvertor occupies the first 4 bytes
            byte[] brcvdDataCount = BitConverter.GetBytes((UInt32)_sFileName.Count());
            bFileBuffer.InsertRange(0, brcvdDataCount);


            //Open TCP/IP Connection
            TcpClient tcpClientSocket = new TcpClient(_sIPAdress, 8080);
            NetworkStream nsNetworkStream = tcpClientSocket.GetStream();
            nsNetworkStream.Write(bFileBuffer.ToArray(), 0, bFileBuffer.Count);
            nsNetworkStream.Close();

        }​​