我看了任何檔案傳輸程式,在傳輸檔案之前接收方都要發送一個OK資訊,發送方收到OK資訊之后才能發送。我把發送接收OK資訊的代碼去掉就不能完整地傳輸檔案呢?下面是我的示例程式,大家能分析下是為什么嗎
發送方
#include "stdafx.h"
#include<iostream.h>
#include<winsock2.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")
int main(){
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2,2), &wsaData)) //初始化WinSock協議堆疊
{ cout<<"Winsock不能被初始化!";
WSACleanup();
return 0;
}
SOCKET sockSer, sockConn; //注意服務器端必須創建兩個套接字
sockSer=socket(AF_INET,SOCK_STREAM,0); //初始化套接字
SOCKADDR_IN addrSer,addrCli; //注意服務器端要創建兩個套接字地址
addrSer.sin_family=AF_INET;
addrSer.sin_port=htons(5566);
addrSer.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
bind(sockSer,(SOCKADDR*)&addrSer,sizeof(SOCKADDR)); //系結套接字
listen(sockSer,5);
int len=sizeof(SOCKADDR);
cout<<"服務器等待客戶端的連接……"<<endl;
sockConn=accept(sockSer,(SOCKADDR*)&addrCli,&len); //接受連接,注意回傳值
if(sockConn==INVALID_SOCKET){
cout<<"服務器接受客戶端連接失敗!"<<endl;
return 0;}
else cout<<"服務器接受客戶端連接成功!"<<endl;
char fileName[256]="C:\\cf.jpg";
char filebuf[1000],OK[3],fsize[50];
/***打開要傳輸的檔案***/
FILE *fp; //創建檔案指標
if((fp=fopen(fileName,"rb"))==NULL) { //以只讀位元組型模式打開檔案
cout << "不能打開檔案: " << fileName << endl;
closesocket(sockConn); //關閉socket,對方等待的recv()函式將回傳0
closesocket(sockSer); WSACleanup();
return 0; } //檔案打開失敗則退出
/***獲取檔案長度***/
fseek(fp,0L,SEEK_END); //將檔案的位置指標移到檔案末尾
long int size=ftell(fp); //獲取當前檔案位置指標值,該值即為檔案長度
fseek(fp,0L,SEEK_SET); //將檔案的位置指標移到檔案開頭
long int fileSize=size;
//fileSize = htonl(size); //將檔案長度存入結構變數fileMsg
itoa(fileSize,fsize,10);
send(sockConn, fsize, strlen(fsize)+1, 0); //發送fileName
cout<<fsize;
/***接收對方發送來的OK資訊***/
if (recv(sockConn, OK, sizeof(OK), 0) <= 0) {
cout << "接收OK失敗,程式退出!\n";
closesocket(sockSer); WSACleanup();
return 0; }
/***發送檔案內容***/
if (strcmp(OK, "OK") == 0) {
while(!feof(fp)) { //當檔案沒有到末尾時
size=fread(filebuf,1,sizeof(filebuf),fp); //每次讀1000位元組
send(sockConn, filebuf, size, 0); //每次寫size個位元組
}
cout << "檔案發送完畢"; //顯示傳輸完成
fclose(fp); } //關閉檔案
closesocket(sockSer);
WSACleanup();
return 0; }
接收方
#include "stdafx.h"
#include<iostream.h>
#include<winsock2.h>
#include <stdio.h>
#include "direct.h" //_mkdir()函式需要
#pragma comment(lib,"ws2_32.lib")
int main(){
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2,2), &wsaData)) {
cout<<"Winsock不能被初始化!";
WSACleanup();
return 0; }
SOCKET sockCli; //創建套接字sockCli
sockCli=socket(AF_INET,SOCK_STREAM,0);
SOCKADDR_IN addrSer; //客戶端只要創建一個套接字地址
addrSer.sin_family=AF_INET;
addrSer.sin_port=htons(5566);
addrSer.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
int res=connect(sockCli,(SOCKADDR*)&addrSer, sizeof(SOCKADDR));
if(res){ cout<<"客戶端連接服務器失敗"<<endl;
return -1; }
else{ cout<<"客戶端連接服務器成功"<<endl; }
char sendbuf[256], recvbuf[256];
long int filelen;
char filedir[200]= "D:\\TANG\\"; //指定接收到的檔案的保存目錄
char ok[3]="OK",fsize[50];
char fileBuffer[1000];//接收檔案資料的緩沖區
/***創建檔案的保存目錄***/
_mkdir(filedir); //_mkdir()用于創建檔案夾
/***接收檔案名及檔案長度資訊***/
if((filelen=recv(sockCli,fsize,sizeof(fsize),0))<=0){
cout<<"未接收到檔案名字及檔案長度!\n";
closesocket(sockCli); WSACleanup();
return 0; }
filelen=atol(fsize);
/***創建檔案準備接收檔案內容***/
char filename[256]="e:\\cf.jpg";
FILE *fp; //創建檔案指標
if((fp=fopen(filename,"wb"))==NULL) {//以只寫方式打開檔案
cout<<"不能打開檔案:"<<filename<<endl;
closesocket(sockCli);
WSACleanup();
return 0; } //檔案打開失敗則退出
cout<<filelen;
send(sockCli,ok,sizeof(ok),0); //發送接收檔案資料的確認資訊
/***接收檔案資料并寫入檔案***/
long int size=0; //接收到的資料長度
do {
size=recv(sockCli,fileBuffer,sizeof(fileBuffer),0);
fwrite(fileBuffer,1,size,fp); //寫入檔案,每次寫size位元組
filelen-=size;
}while(size!=0 && filelen>0); //回圈條件是size!=0 && filelen>0
/***檔案傳輸完成結束程式***/
cout<<"接收檔案"<<filename<<"完畢!\n";
fclose(fp);
while(1){
cout<<"客戶端說:>";
cin>>sendbuf;
if(strcmp(sendbuf,"bye")==0){
break;}
send(sockCli,sendbuf,strlen(sendbuf)+1,0);
if(recv(sockCli,recvbuf,256,0)>0)
cout<<"服務器說:>"<<recvbuf<<endl;
else {cout<<"服務器已關閉連接"<<endl;
break;}
}
closesocket(sockCli);
WSACleanup();
return 0;
}
uj5u.com熱心網友回復:
個人理解 就是用Ok做了個簡單的分界協議uj5u.com熱心網友回復:

可以去掉。直接發檔案。
uj5u.com熱心網友回復:
去掉了,直接發檔案會出錯,接收到的檔案少了幾Kb。uj5u.com熱心網友回復:
接收端接收到檔案長度以后,按這個長度來回圈recv接收后續的資料。uj5u.com熱心網友回復:
我是說發送OK標記的作用,發送檔案長度的作用,那我倒是知道的uj5u.com熱心網友回復:
你不會加斷點除錯嗎?uj5u.com熱心網友回復:
這就是神秘莫測的協議uj5u.com熱心網友回復:
我用VC6,確實不知道怎么加斷點除錯。uj5u.com熱心網友回復:
學習研究一下
uj5u.com熱心網友回復:
這和它們之間的協議有關吧uj5u.com熱心網友回復:
我發現異步接收檔案的程式,可不需要發送和接收OK資訊uj5u.com熱心網友回復:
請問你這個程式怎么運行?小白不懂,同一專案下,兩個.c檔案都有main函式,怎么運行?uj5u.com熱心網友回復:
了解下檔案傳輸協議Xmodem,Ymodem。接收者是根據協議決議資料的。uj5u.com熱心網友回復:
要建立兩個專案,一個是服務器端,一個客戶端,才能相互通信
uj5u.com熱心網友回復:
我這個不異步通信的檔案傳輸程式確實不需要發送OK訊息,也可以收發檔案。所以我猜想發送OK資訊,可能是為了隔斷前面的發送檔案大小/檔案名 和后面的 發送 檔案內容, 使 前 后的發送資料不會發送粘包現象,我這只是猜想,不知道如何證實。uj5u.com熱心網友回復:
我這個 異步通信的檔案傳輸程式https://download.csdn.net/download/wuxia2118/11522767
uj5u.com熱心網友回復:
你剛開始學,還是想辦法先除錯起來,還有一個簡單或者傻的辦法,就是發送任何資料之前先發送一個整數的長度,表示下來要發送多長的資料塊,接收的時候先接收4個位元組的整數長度,然后就知道剩余還有多少資料需要接收,在回圈接收完剩余的資料就行。char szBuf[1024] ={0};
strcpy(szBuf,filebuf,size);
int iDataSize= size;
send(sock,(char*)&iDataSize,sizeof(iDataSize),0);
send(sock,szBuf,iDataSize,0);
接收端:
int iDataSize= 0;
char szBuf[1024] ={0};
int iRet = recv(sock,(char*)&iDataSize,sizeof(iDataSize),0);
if(iRet ==sizeof(iDataSize))
{
int iTotalRecvLen = 0;
while(iTotalRecvLen <iDataSize)
{
iRet = recv(sock,szBuf+,iDataSize-iTotalRecvLen,0);
if(iRet<=0)
break;
iTotalRecvLen+=iRet;
}
}
我博客里寫了一套開源的通信框架,你有空可以看看,不過對你來講,可能比較復雜。
https://blog.csdn.net/moonbamboo/article/details/99286765
uj5u.com熱心網友回復:
不可能的,發送OK不是必須的,完全可以去掉,只要明確檔案發送的起點及終點(可以指明檔案長度)
uj5u.com熱心網友回復:
請問,windows上的IO重定向,可以直接把打開的檔案描述符定向到socket描述符嗎轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/37108.html
標籤:網絡編程
上一篇:CString Format問題
