本文學習相關資料:
C/C++ socket編程教程
環境:vs2015
源碼:本文代碼
這次來試一下使用TCP來傳輸文件,其實傳輸數據和差不多,就是多一個讀取文件,和一個寫文件而已。
服務端
int readlan = 100;
std::ifstream infile;SOCKET client = accept(servSock, (sockaddr*)&clntAddr, &nSize);//獲取
do {//接收獲取的文件名recv(client, buf, maxlen, 0);std::cout << buf << std::endl;//打開文件infile.open(buf, std::ios::binary | std::ios::in);if (infile.is_open()) { //如果打開文件成功就退出,否則繼續等待break;}else {std::cout << "文件打開失敗" << std::endl;send(client, "False", 6, 0);}
} while (1);if (infile.is_open()) {
//打開文件成功,通知客戶端接收文件send(client, "True", 5, 0);std::cout << "準備發送文件" << std::endl;int num = 0;//獲取文件的大小infile.seekg(0, std::ios::end);int length = infile.tellg();//設置文件指針在第一個位置infile.seekg(std::ios::beg);//循環讀取while (length > 0) {std::cout << "正在發送文件,目前還剩余" << length << "字節" << std::endl;memset(&buf, maxlen, 0);//讀取內容,每次讀readlen個字節if (length >= readlen) { length -= readlen;infile.read(buf, readlen);num = readlen;}else {num = length;infile.read(buf, length);length = 0;}//發送內容send(client, buf, num, 0);}
}
else {std::cout << "文件打開失敗,即將關閉" << std::endl;
}
//發送斷開連接信息
shutdown(client, SD_SEND);
//關閉文件和套接字
infile.close();
closesocket(client);
客戶端
std::ofstream f;
std::string fileName;//連接到服務端
connect(client, (sockaddr*)&servAddr, sizeof(sockaddr));
while (1) {memset(buf, maxlen, 0);std::cout << "請輸入要下載的文件名稱:";//輸入文件名稱std::cin >> fileName;send(client, fileName.c_str(), fileName.size() + 1, 0);recv(client, buf, readlen, 0);if (strcmp(buf, "True") == 0) {break;}
}
//打開文件
f.open(fileName.c_str(), std::ios::binary | std::ios::out);
while (1) {int nlen = recv(client, buf, readlen, 0);if (nlen <= 0) {std::cout << "文件接收完畢!" << std::endl;break;}else {//寫入文件f.write(buf, nlen); f.flush();}
}
f.close();
closesocket(client);
可能會注意到這里服務端能接收到連接,是因為調用了listen,但是客戶端沒有listen,服務端是怎么知道要把數據發送到哪里呢?
原來服務端在調用accept的時候,就已經獲取到了客戶端的IP地址和端口號,保存在了clntAddr。
那么客戶端又沒有bind 又怎么來IP地址和端口呢?
簡單地來說是當客戶端調用connect的時候,系統自動分配的,畢竟需要個IP地址和端口才能進行3次握手。