我正在開發一個專案,該專案應該將檔案作為二進制塊讀取并將其發送給客戶端。
服務器端代碼:
FILE *src = fopen("Video.mp4","rb"); // size of the video is 158 MB
int buffer = (1024*8); //chunk size of 8kb
char filebyte[buffer];
while(!feof(src)){
filebyte[0]=0; // Clearing the byte array to avoid overlapping
fread(filebyte,buffer,1,src);
send(acpt,filebyte,buffer,0);
filebyte[0]=0; // Clearing the byte array to avoid overlapping
}
fclose(src);
客戶端代碼
FILE *target = fopen("ReceivedVideo","wb");
int buffer = (1024*8) ; // chunk size of 8kb
char fileByte[buffer];
int stat;
while(1){
fileByte[0]=0; // Clearing the byte array to avoid overlapping
stat = recv(soc,fileByte,buffer,0);
fwrite(fileByte,buffer,1,target);
fileByte[0]=0; // Clearing the byte array to avoid overlapping
if(stat<0){
break;
}
}
fclose(target);
但是每當我發送任何視頻或任何其他檔案時,客戶端的檔案輸出大小總是大于發件人實際發送的原始檔案。
我發送了一個 158 MB 的視頻。傳輸完成后,客戶端生成的檔案大小為 160 MB,每當我嘗試在客戶端目錄打開接收到的視頻時,視頻播放器都會拋出錯誤。
然后我嘗試發送一個 46KB 的小 .exe 檔案。不得不再次面對同樣的命運。在客戶端生成的 .exe 消耗更多位元組,打開時會引發錯誤。
最后我發送了一個 16kb 的 JPEG 影像檔案。在客戶端,照片消耗了 19kb 的存盤空間,與原始影像相比,我可以清楚地看到接收到的圖片中存在一些像素錯位或模糊或類似的東西,但至少,影像查看器這次沒有拋出錯誤.
我發現的問題是,雖然我像這樣清除了服務器端和客戶端的塊存盤
filebyte[0]=0; // On server side
fileByte[0]=0; // On client side
仍然在服務器或客戶端收到的位元組(我真的不知道是哪一方導致了問題,但有點重疊是問題 - 根據我的說法)以某種方式重疊并損壞檔案并使其大小變大。
我將完整的服務器和客戶端代碼放在下面。
完整的服務器端代碼:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <windows.h>
#include <winsock2.h>
#define port 8080
int main(){
int buffer = (1024)*8;
WSADATA ws;
WSAStartup(MAKEWORD(2,2),&ws);
SOCKET soc,acpt;
sockaddr_in config;
config.sin_family = AF_INET;
config.sin_addr.s_addr = inet_addr("0.0.0.0");
config.sin_port = htons(port);
/*char* msg = new char[buffer];
strcpy(msg,"Hello from Server"); */
soc = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
bind(soc,(sockaddr*)&config,sizeof(config));
listen(soc,1);
acpt = accept(soc,0,0);
FILE *src;
char filename[100]="Video.mp4";
char filebyte[buffer];
src = fopen(filename,"rb");
while(!feof(src)){
filebyte[0]=0;
fread(filebyte,buffer,1,src);
send(acpt,filebyte,buffer,0);
filebyte[0]=0;
}
fclose(src);
std::cout << "Press Enter to exit" <<std::endl;
//getchar();
return 0;
}
完整的客戶端代碼
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <windows.h>
#include <winsock2.h>
#define port 8080
int main(){
WSADATA ws;
WSAStartup(MAKEWORD(2,2),&ws);
int buffer = (1024)*8;
// char incoming[buffer];
sockaddr_in config;
config.sin_family = AF_INET;
config.sin_addr.s_addr = inet_addr("127.0.0.1");
config.sin_port = htons(port);
SOCKET soc;
soc = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
int err = connect(soc,(sockaddr*)&config,sizeof(config));
if(err!=0){
std::cout << "Could not connect" <<std::endl;
}else{
std::cout << "Connected Successfully" <<std::endl;
}
FILE *target;
int stat;
char fileByte[buffer]={0};
while(1){
fileByte[0]=0;
stat = recv(soc,fileByte,buffer,0);
fwrite(fileByte,buffer,1,target);
fileByte[0]=0;
if(stat<0){
break;
}
}
std::cout << strlen(fileByte) << std::endl;
fclose(target);
return 0;
}
uj5u.com熱心網友回復:
我兩次看到相同的問題,即“位元組數”。
試試這個:
int32_t readBytes;
while((readBytes = fread(filebyte, 1, buffer, src)) > 0)
send(acpt,filebyte, readBytes,0);
對于服務器端和客戶端:
int stat;
while((stat = recv(soc,fileByte,buffer,0)) > 0)
fwrite(fileByte,1, stat,target);
此代碼“不在我的腦海中”,因此您可能需要相應地對其進行調整。
解釋發生了什么:fread將回傳“讀取的元素數”(有關更多詳細資訊,請參見手冊頁),它是檔案最后一個塊的“小于緩沖區”。
如果您總是發送整個緩沖區,這將導致“填充輸出”,最后一部分是“上次讀取期間檔案中該位置的任何內容”,這會導致您描述的問題。
同樣,如果您總是寫入整個緩沖區,則結果檔案將以相同的方式填充。
編輯:正如我注意到的那樣,您的代碼還有另一個缺陷,即您的客戶端將繼續等待更多資料,直到服務器關閉連接,這不會發生。
為此,您需要致電
shutdown(acpt, 2);
closesocket(acpt);
在讀/發送塊之后。
或者,如果要保持連接打開,則需要向協議添加其他資訊。
uj5u.com熱心網友回復:
除了其他答案/評論-
發送檔案完成后,服務器代碼并未關閉 TCP 連接,因此客戶端不知道何時在檔案末尾終止其讀取回圈。
服務器應該要么
在發送檔案資料之前發送檔案大小。然后客戶端可以先讀取大小,然后在接收到指定數量的位元組時停止回圈。
在每個緩沖區之前發送一個固定的標頭,包含緩沖區大小。然后它可以在檔案完成后發送一個長度為 0 的緩沖區。然后客戶端可以讀取每個頭和緩沖區,直到它讀取 0 長度緩沖區的頭。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/382509.html
