2015-09-06 37 views
1

我必須開發一個簡單的TCP文件傳輸客戶端作爲練習/演示的一部分,但我在數據傳輸方面遇到了問題。使用TCP文件傳輸客戶端發送時遇到問題

我已經提供了TCP文件服務器,它將接收傳入的文件,我必須編寫一個客戶端,它將連接併發送文件到服務器。到目前爲止,我已經成功地將所選文件的數據轉換爲準備好傳輸併成功打開連接然後發送數據的格式,但是即使在接收的服務器上遇到問題 - 我也不允許更改服務器的代碼,並因此應該更改我的客戶端代碼,以便發送的數據可以由服務器解釋。下面是我使用的代碼(有些被冷落是簡單的開銷,比如輸入框獲取IP地址等):

鏈接,TCP服務器與解決方案(如果你喜歡):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是剛剛從打開文件對話框完整的文件路徑+文件名。

這裏是服務器的負載方法得到的東西去:

 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(); 
      } 
     } 
    } 

然後lasty這裏的處理器線程方法:

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); 
     } 
    } 

現在我已經調試,並且至今我可以確定,第一次我可以看到一個問題是當w e試圖確定代碼讀取的文件名長度int iFileNameLength = BitConverter.ToInt32(rcvdData, 0); - 當調試這個變量總是被確定爲'0',我認爲這是不正確的?我不確定。需要實現的所需結果是服務器應該接收文件,並且在成功傳輸後,文件名應顯示在列表框中。

這裏是在我遇到問題的屏幕截圖:

我們可以看到,字節肯定的答覆: Received Bytes

注意文件名不能使用文件名長度檢索和偏移量: Blank file name

並且這樣,就會出現以下錯誤: Error

我的經驗和專長在別處,這是我第一次在這種模式下進行編碼(文件傳輸通過網絡)。然而,我的確有OSI模型和TCP/IP協議棧的理論知識,但從來沒有編碼過這樣的東西。給我的一個注意事項是,服務器的編碼假定它將在特定的PC上執行,並且如果絕對必要,我可以更改服務器應用程序的代碼。

+0

'dataByte.CopyTo(rcvdData,I);'是錯誤的,'iRcvdBytes <= iBlockSize',你把它當作'iRcvdBytes == iBlockSize || iRcvdBytes == 0'。 'dataByte'在你拷貝到'rcvdData'的數組末尾有「垃圾數據」。 –

回答

1

試試這個。您必須在客戶端反過來思考,並使用列表使事情變得更容易。

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(); 

     }​​ 
+0

我明白了,但有沒有辦法做到這一點,而無需更改服務器代碼?就像我在通過客戶端發送數據時如何使用ASCII編碼而不是使用字節? –

+0

我沒有更改服務器代碼。服務器正在接收字節,我正在發送字節。服務器期望文件名長度是前四個字節,然後是文件名,然後是數據。 – jdweng

+0

理解,但我該如何解決這個問題,我如何在客戶端做相反的事情?我更新了我的帖子,以包括我的問題的屏幕截圖。對不起,我對這個問題深感不滿。 –

1

有兩件事與服務器代碼,你應該知道的

/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編碼,這意味着你不能上傳二進制數據。

+0

我明白了。我將如何(1)在發送時添加字節計數和(2)使用ASCII編碼對數據進行編碼?謝謝。 –