代碼如下:
//功能:使用SOCKET傳輸文件的代碼。
/*server.h*/
#pragma註釋(lib," WS2_32 ")
#包括
#包括
//#包含
#包括
#ifndef COMMONDEF_H
#定義COMMONDEF_H
# define max _ packet _ size 10240//數據包的最大長度,以sizeof(char)為單位。
#define MAXFILEDIRLENGTH 256 //存儲文件路徑的最大長度。
#定義端口4096 //端口號
# define server _ IP " 127 . 0 . 0 . 1 "//服務器的IP地址。
//各種消息的宏定義
#define INVALID_MSG -1 //無效消息ID
#define MSG_FILENAME 1 //文件名
#define MSG_FILELENGTH 2 //傳輸文件的長度
#define MSG_CLIENT_READY 3 //客戶端準備接收文件。
#定義消息_文件4 //傳輸文件
#define MSG_SENDFILESUCCESS 5 //文件傳輸成功。
# define msg _ openfile _ error 10//無法打開文件,可能是因為文件路徑錯誤,找不到文件。
# define msg _ filealreadyexit _ error 11//要保存的文件已經存在。
CCSDef級
{
公共:
#pragma pack(1) //按照1字節對齊結構的數據,節省空間。
//消息頭
結構TMSG _標題
{
char cMsgID//消息ID
TMSG _標頭(char MsgID = INVALID_MSG)
:cMsgID(MsgID)
{
}
};
//請求傳輸的文件名
//客戶端發送給服務器的是完整的路徑名。
//服務器返回給客戶端的是文件名。
結構TMSG _文件名:公共TMSG _頭
{
char SZ filename[256];//保存文件名的字符數組。
TMSG文件名()
:TMSG標題(消息文件名)
{
}
};
//傳輸文件長度
結構TMSG _文件長度:公共TMSG _頭
{
長度長;
TMSG文件長度(長長度)
:TMSG標題(消息文件長度),長度(長度)
{
}
};
//客戶端準備好了,需要服務器端開始傳輸文件。
結構TMSG _客戶端_就緒:公共TMSG _頭
{
TMSG客戶端就緒()
:TMSG標題(消息客戶端就緒)
{
}
};
//傳輸文件
結構TMSG _文件:公共TMSG _標題
{
Union // union確保數據包大小不大於MAX_PACKET_SIZE * sizeof(char)。
{
char SZ buff[MAX _ PACKET _ SIZE];
結構體
{
int nStart
int nSize
char SZ buff[MAX _ PACKET _ SIZE-2 * sizeof(int)];
} tFile
};
TMSG文件()
:TMSG標題(消息文件)
{
}
};
//文件傳輸成功。
結構TMSG _發送文件成功:公共TMSG _頭
{
TMSG _發送文件成功()
:TMSG標題(消息發送文件成功)
{
}
};
//發送錯誤信息,包括:
// MSG_OPENFILE_ERROR:無法打開文件。
// MSG_FILEALREADYEXIT_ERROR:要保存的文件已經存在。
結構TMSG _錯誤_消息:公共TMSG _標題
{
TMSG錯誤消息
:TMSG _頭(cErrorMsg)
{
}
};
#雜註包()
};
#endif
/*server.h*/
#pragma註釋(lib," WS2_32 ")
#包括
#包括
//#包含
#包括
#ifndef COMMONDEF_H
#定義COMMONDEF_H
# define max _ packet _ size 10240//數據包的最大長度,以sizeof(char)為單位。
#define MAXFILEDIRLENGTH 256 //存儲文件路徑的最大長度。
#定義端口4096 //端口號
# define server _ IP " 127 . 0 . 0 . 1 "//服務器的IP地址。
//各種消息的宏定義
#define INVALID_MSG -1 //無效消息ID
#define MSG_FILENAME 1 //文件名
#define MSG_FILELENGTH 2 //傳輸文件的長度
#define MSG_CLIENT_READY 3 //客戶端準備接收文件。
#定義消息_文件4 //傳輸文件
#define MSG_SENDFILESUCCESS 5 //文件傳輸成功。
# define msg _ openfile _ error 10//無法打開文件,可能是因為文件路徑錯誤,找不到文件。
# define msg _ filealreadyexit _ error 11//要保存的文件已經存在。
CCSDef級
{
公共:
#pragma pack(1) //按照1字節對齊結構的數據,節省空間。
//消息頭
結構TMSG _標題
{
char cMsgID//消息ID
TMSG _標頭(char MsgID = INVALID_MSG)
:cMsgID(MsgID)
{
}
};
//請求傳輸的文件名
//客戶端發送給服務器的是完整的路徑名。
//服務器返回給客戶端的是文件名。
結構TMSG _文件名:公共TMSG _頭
{
char SZ filename[256];//保存文件名的字符數組。
TMSG文件名()
:TMSG標題(消息文件名)
{
}
};
//傳輸文件長度
結構TMSG _文件長度:公共TMSG _頭
{
長度長;
TMSG文件長度(長長度)
:TMSG標題(消息文件長度),長度(長度)
{
}
};
//客戶端準備好了,需要服務器端開始傳輸文件。
結構TMSG _客戶端_就緒:公共TMSG _頭
{
TMSG客戶端就緒()
:TMSG標題(消息客戶端就緒)
{
}
};
//傳輸文件
結構TMSG _文件:公共TMSG _標題
{
Union // union確保數據包大小不大於MAX_PACKET_SIZE * sizeof(char)。
{
char SZ buff[MAX _ PACKET _ SIZE];
結構體
{
int nStart
int nSize
char SZ buff[MAX _ PACKET _ SIZE-2 * sizeof(int)];
} tFile
};
TMSG文件()
:TMSG標題(消息文件)
{
}
};
//文件傳輸成功。
結構TMSG _發送文件成功:公共TMSG _頭
{
TMSG _發送文件成功()
:TMSG標題(消息發送文件成功)
{
}
};
//發送錯誤信息,包括:
// MSG_OPENFILE_ERROR:無法打開文件。
// MSG_FILEALREADYEXIT_ERROR:要保存的文件已經存在。
結構TMSG _錯誤_消息:公共TMSG _標題
{
TMSG錯誤消息
:TMSG _頭(cErrorMsg)
{
}
};
#雜註包()
};
#endif
/*server.cpp*/
#包含“server.h”
char g _ szNewFileName[MAXFILEDIRLENGTH];
char g _ SZ buff[MAX _ PACKET _ SIZE+1];
長g _ lLength
char * g _ pBuff = NULL
//初始化套接字庫
bool init socket();
//關閉套接字庫
bool close socket();
//解析消息進行相應處理。
bool ProcessMsg(套接字客戶端);
//監聽客戶端的消息
void ListenToClient();
//打開文件
bool OpenFile(CCS def::TMSG _ HEADER * pMsgHeader,SOCKET s client);
//傳輸文件
bool發送文件(套接字客戶端);
//將文件讀入緩沖區
bool ReadFile(SOCKET s client);
int main()
{
init socket();
ListenToClient();
close socket();
返回0;
}
void ListenToClient()
{
//創建套接字套接字
SOCKET sListen = ::socket(AF_INET,SOCK_STREAM,IP proto _ TCP);
if (SOCKET_ERROR == sListen)
{
printf("初始化套接字錯誤!\ n ");
返回;
}
//將套接字綁定到本地地址
sockaddr _ in sin
sin.sin _ family = AF _ INET
sin . sin _ PORT = htons(PORT);
sin.sin_addrS_un。S _ addr = INADDR _ ANY
if (::bind(sListen,(LPSOCKADDR)& amp;sin,sizeof(sockaddr _ in))= = SOCKET _ ERROR)
{
printf("綁定錯誤!\ n ");
返回;
}
//設置套接字進入偵聽狀態。
if (::listen(sListen,10) == SOCKET_ERROR)
{
printf("監聽錯誤!\ n ");
返回;
}
printf("傾聽客戶...\ n ");
//循環接收客戶端的連接請求。
sockaddr _ in ClientAddr
int nAddrLen = sizeof(sockaddr _ in);
套接字sClient
while(INVALID _ SOCKET = =(s client =::accept(s listen,(sockaddr *)& amp;client addr & amp;nAddrLen)))
{
}
while (true == ProcessMsg(sClient))
{
}
//關閉與客戶端的連接。
* close socket(s client);
* close socket(s listen);
}
布爾初始化套接字()
{
//初始化套接字dll
WSADATA wsaData
WORD socketVersion = MAKEWORD(2,2);
if (::WSAStartup(socketVersion,& ampwsaData)!= 0)
{
printf("Init socket dll錯誤\ n ");
返回false
}
返回true
}
bool CloseSocket()
{
//釋放winsock庫
* WSACleanup();
if (NULL!= g_pBuff)
{
delete[]g _ pBuff;
g _ pBuff = NULL
}
返回true
}
bool ProcessMsg(套接字客戶端)
{
int nRecv = ::recv(sClient,g_szBuff,MAX_PACKET_SIZE + 1,0);
if(nRecv & gt;0)
{
g _ SZ buff[nRecv]= ' \ 0 ';
}
//解析命令
CCS def::TMSG _ HEADER * pMsgHeader =(CCS def::TMSG _ HEADER *)g _ szBuff;
開關(pMsgHeader-& gt;cMsgID)
{
案例消息_文件名://文件名
{
OpenFile(pMsgHeader,s client);
}
打破;
Case MSG_CLIENT_READY: //客戶端準備好傳輸文件。
{
發送文件(s client);
}
打破;
Case MSG_SENDFILESUCCESS: //文件傳輸成功。
{
printf("發送文件成功!\ n ");
返回false
}
打破;
case msg _ file alreadyexit _ error://要保存的文件已經存在。
{
printf("準備發送的文件已經存在!\ n ");
返回false
}
打破;
}
返回true
}
bool讀取文件(套接字客戶端)
{
if (NULL!= g_pBuff)
{
返回true
}
//打開文件
FILE * pFile
if(null = =(pfile = fopen(g _ sznewfilename," Rb))//無法打開文件。
{
printf("找不到文件,請求客戶端再次輸入文件名\ n ");
CCS def::TMSG _錯誤_消息tMsgErrorMsg(消息_打開文件_錯誤);
* send(s client,(char *)(& amp;tMsgErrorMsg),sizeof(CCS def::TMSG _錯誤_MSG),0);
返回false
}
//將文件的長度發送回客戶端。
fseek(pFile,0,SEEK _ END);
g _ lLength = ftell(pFile);
printf("文件長度= %d\n ",g _ l Length);
CCS def::TMSG _文件長度TMSG文件長度(g _ lLength);
* send(s client,(char *)(& amp;tMsgFileLength),sizeof(CCS def::TMSG _文件長度),0);
//處理文件的完整路徑名,分解文件名。
char szDrive[_MAX_DRIVE],szDir[_MAX_DIR],szFname[_MAX_FNAME],szExt[_ MAX _ EXT];
_splitpath(g_szNewFileName,szDrive,szDir,szFname,szExt);
strcat(szFname,szExt);
CCS def::TMSG _文件名tMsgFileName
strcpy(tMsgFileName.szFileName,SZ fname);
printf("發送文件名:%s\n ",tmsgfilename . SZ filename);
* send(s client,(char *)(& amp;tMsgFileName),sizeof(CCS def::TMSG _文件名),0);
//分配緩沖區來讀取文件內容
g _ pBuff = new char[g _ l length+1];
if (NULL == g_pBuff)
{
返回false
}
fseek(pFile,0,SEEK _ SET);
fread(g_pBuff,sizeof(char),g_lLength,pFile);
g _ pBuff[g _ l length]= ' \ 0 ';
fclose(pFile);
返回true
}
//打開文件
布爾開放文件(CCS def::TMSG _頭* pMsgHeader,套接字客戶端)
{
CCS def::TMSG _文件名* prequestfilename msg =(CCS def::TMSG _文件名*)pMsgHeader;
//對文件路徑名做壹些處理。
char *p1,* p2
for(p 1 = pRequestFilenameMsg-& gt;szFileName,p2 = g _ szNewFileName
'\0' != * p 1;
++p1,++p2)
{
if ('\n '!= *p1)
{
* p2 = * p 1;
}
if ('\\' == *p2)
{
*(++ p2)= ' \ \ ';
}
}
* p2 = ' \ 0
ReadFile(s client);
返回true
}
//傳輸文件
bool發送文件(套接字客戶端)
{
if (NULL == g_pBuff)
{
ReadFile(s client);
}
int nPacketBufferSize = MAX _ PACKET _ SIZE-2 * sizeof(int);//每個數據包中存儲文件的緩沖區的大小。
//如果文件長度大於每個包可以傳輸的緩沖區長度,就分塊傳輸。
for(int I = 0;我& ltg _ lLengthi += nPacketBufferSize)
{
CCS def::TMSG _ FILE tMsgFile;
tmsgfile . tfile . nstart = I;
if(I+nPacketBufferSize+1 & gt;g _ lLength)
{
tmsgfile . tfile . nsize = g _ l length-I;
}
其他
{
tmsgfile . tfile . nsize = nPacketBufferSize;
}
//printf("start = %d,size = %d\n ",tMsgFile.tFile.nStart,tmsgfile . tfile . nsize);
memcpy(tMsgFile.tFile.szBuff,g_pBuff + tMsgFile.tFile.nStart,tmsgfile . tfile . nsize);
* send(s client,(char *)(& amp;tMsgFile),sizeof(CCS def::TMSG _文件),0);
睡眠(0.5);
}
delete[]g _ pBuff;
g _ pBuff = NULL
返回true
}
/*client.h與server.h相同*/
/*client.cpp*/
#包含“client.h”
long g _ l length = 0;
char * g _ pBuff = NULL
char g _ SZ filename[MAXFILEDIRLENGTH];
char g _ SZ buff[MAX _ PACKET _ SIZE+1];
套接字g _ sClient
//初始化套接字庫
bool init socket();
//關閉套接字庫
bool close socket();
//將用戶輸入的文件路徑發送給服務器。
bool SendFileNameToServer();
//與服務器連接。
bool ConectToServer();
//無法打開文件。
bool openfile error(CCS def::TMSG _ HEADER * pMsgHeader);
//為寫入文件分配空間
bool AllocateMemoryForFile(CCS def::TMSG _ HEADER * pMsgHeader);
//寫文件
bool write tofile(CCS def::TMSG _ HEADER * pMsgHeader);
//處理服務器發送的消息。
bool ProcessMsg();
int main()
{
init socket();
ConectToServer();
close socket();
返回0;
}
//初始化套接字庫
布爾值InitSocket()
{
//初始化套接字dll
WSADATA wsaData
WORD socketVersion = MAKEWORD(2,2);
if (::WSAStartup(socketVersion,& ampwsaData)!= 0)
{
printf("Init socket dll錯誤\ n ");
退出(-1);
}
返回true
}
//關閉套接字庫
bool CloseSocket()
{
//關閉套接字
* close socket(g _ s client);
//釋放winsock庫
* WSACleanup();
返回true
}
//連接服務器傳輸文件。
布爾連接服務器()
{
//初始化套接字套接字
if(SOCKET _ ERROR = =(g _ s client =::SOCKET(AF _ INET,SOCK_STREAM,IPPROTO_TCP)))
{
printf("初始化套接字錯誤!\ n ");
退出(-1);
}
sockaddr _ in servAddr
servAddr.sin _ family = AF _ INET
serv addr . sin _ PORT = htons(PORT);
servAddr.sin_addr。S_un。s _ addr =::inet _ addr(SERVER _ IP);
if(INVALID _ SOCKET = =(::connect(g _ s client,(sockaddr *)& amp;servAddr,sizeof(sockaddr_in))))
{
printf("連接到服務器錯誤!\ n ");
退出(-1);
}
//將輸入文件路徑傳輸到服務器端。
SendFileNameToServer();
//從服務器接收信息,直到文件保存成功。
while (true == ProcessMsg())
{
}
返回true
}
//將用戶輸入的文件路徑發送給服務器。
bool SendFileNameToServer()
{
char SZ filename[MAXFILEDIRLENGTH];
printf("輸入文件目錄:");
fgets(szFileName,MAXFILEDIRLENGTH,stdin);
//將文件路徑發送給服務器。
CCSDef::TMSG _文件名tMsgRequestFileName
strcpy(tmsgrequestfilename . SZ filename,SZ filename);
if(SOCKET _ ERROR = =::send(g _ s client,(char *)(& amp;tMsgRequestFileName),sizeof(CCS def::TMSG _文件名),0))
{
printf("發送文件名錯誤!\ n ");
退出(-1);
}
返回true
}
//處理服務器發送的消息。
bool ProcessMsg()
{
CCS def::TMSG _ HEADER * pMsgHeader;
int nRecv = ::recv(g_sClient,g_szBuff,MAX_PACKET_SIZE + 1,0);
pMsgHeader =(CCS def::TMSG _ HEADER *)g _ szBuff;
開關(pMsgHeader-& gt;cMsgID)
{
Case MSG_OPENFILE_ERROR: //打開文件時出錯。
{
openfile error(pMsgHeader);
}
打破;
Case MSG_FILELENGTH: //文件的長度。
{
if(0 = = g _ length)
{
g _ length =((CCS def::TMSG _文件長度*)pMsgHeader)-& gt;lLength
printf("文件長度:%d\n ",g _ l Length);
}
}
打破;
案例消息_文件名://文件名
{
返回AllocateMemoryForFile(pMsgHeader);
}
打破;
Case MSG_FILE: //傳輸文件,寫文件成功後退出本功能。
{
if (WriteToFile(pMsgHeader))
{
返回false
}
}
打破;
}
返回true
}
//無法打開文件。
bool openfile error(CCS def::TMSG _ HEADER * pMsgHeader)
{
if (NULL!= g_pBuff)
返回true
斷言(NULL!= pMsgHeader);
printf("找不到文件!請重新輸入!\ n ");
//重新輸入文件名。
SendFileNameToServer();
返回true
}
//查找要保存的文件是否已經存在,分配壹個緩沖區保存文件。
bool AllocateMemoryForFile(CCS def::TMSG _ HEADER * pMsgHeader)
{
斷言(NULL!= pMsgHeader);
if (NULL!= g_pBuff)
{
返回true
}
CCS def::TMSG _文件名* prequestfilename msg =(CCS def::TMSG _文件名*)pMsgHeader;
printf("文件名:%s\n ",prequest filename msg-& gt;SZ filename);
//將文件路徑設置為c盤根目錄。
strcpy(g_szFileName," c:\ \ ");
strcat(g_szFileName,prequest filename msg-& gt;SZ filename);
//查找是否已經存在同名文件,如果有錯誤就退出。
FILE * pFile
if (NULL!= (pFile = fopen(g_szFileName," r "))
{
//文件已經存在。您需要輸入壹個新文件。
printf("文件已經存在!\ n ");
CCS def::TMSG _錯誤_消息tMsgErrorMsg(消息_文件已就緒_錯誤);
* send(g _ s client,(char *)(& amp;tMsgErrorMsg),sizeof(CCS def::TMSG _錯誤_MSG),0);
fclose(pFile);
返回false
}
//分配緩沖區開始接收文件,如果分配成功,向服務器發送開始傳輸文件的請求。
g _ pBuff = new char[g _ l length+1];
if (NULL!= g_pBuff)
{
memset(g_pBuff,' \0 ',g _ l length+1);
printf("現在準備好獲取文件%s!\n ",pRequestFilenameMsg-& gt;SZ filename);
CCS def::TMSG _客戶端_就緒tMsgClientReady
if(SOCKET _ ERROR = =::send(g _ s client,(char *)(& amp;tMsgClientReady),sizeof(CCS def::TMSG _客戶端_就緒),0))
{
printf("發送錯誤!\ n ");
退出(-1);
}
}
其他
{
printf("為文件錯誤分配內存!\ n ");
退出(-1);
}
返回true
}
//寫文件
布爾寫文件(CCS def::TMSG _頭*pMsgHeader)
{
斷言(NULL!= pMsgHeader);
CCS def::TMSG _文件* pMsgFile =(CCS def::TMSG _文件*)pMsgHeader;
int nStart = pMsgFile-& gt;tFile.nStart
int nSize = pMsgFile-& gt;tFile.nSize
memcpy(g_pBuff + nStart,pMsgFile-& gt;tFile.szBuff,nSize);
if (0 == nStart)
{
printf("將文件保存到緩沖區...\ n ");
}
memcpy(g_pBuff + nStart,pMsgFile-& gt;tFile.szBuff,nSize);
//printf("start = %d,size = %d\n ",nStart,nSize);
//如果文件已經保存到緩沖區,則寫入文件。
if(nStart+nSize & gt;= g _ lLength)
{
printf("寫入磁盤....\ n ");
//寫文件
FILE * pFile
pFile = fopen(g_szFileName," w+b ");
fwrite(g_pBuff,sizeof(char),g_lLength,pFile);
delete[]g _ pBuff;
g _ pBuff = NULL
fclose(pFile);
//保存文件並成功向服務器發送消息退出服務器。
CCS def::TMSG _發送文件成功tMsgSendFileSuccess
while(SOCKET _ ERROR = =::send(g _ s client,(char *)(& amp;tMsgSendFileSuccess),sizeof(CCS def::TMSG _ SENDFILESUCCESS),0))
{
}
printf("保存文件%s成功!\n ",g _ SZ filename);
返回true
}
其他
{
返回false
}
}