以下用C++代码实现了文件的发送与接收
服务器端
#include <iostream>
#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
//缓存大小设置不能超过2M
#define BUFF_SIZE (1024 * 1024)
#define FILE_NAME_LENGTH 1024
int s; /* socket for accepting connections */
int ns; /* socket connected to client */
int exitFunc() {
closesocket(s);
closesocket(ns);
return 0;
}
long long int getFileSize(const char* filePath) {
FILE* f;
f = fopen(filePath, "rb");
if (NULL == f) {
printf("getFileSize fopen error\n");
return -1;
}
if (0 != fseek(f, 0, SEEK_END)) {
printf("getFileSize fseek error\n");
return -1;
}
long long int fileSize = ftell(f);
if (fileSize < 0) {
printf("ftell error\n");
}
printf("fileSize:%lld\n", fileSize);
fclose(f);
return fileSize;
}
char* getFileName(const char* filePath) {
bool bFound = false;
char* buff = new char[1024];
memset(buff, 0, 1024);
while (!bFound) {
int lastIndex = 0;
for (int i = 0; i < strlen(filePath); ++i) {
if (filePath[i] == '\\' || filePath[i] == '/') {
lastIndex = i;
}
}
for (int i = lastIndex + 1; i < strlen(filePath); ++i) {
buff[i - lastIndex - 1] = filePath[i];
}
bFound = true;
}
return buff;
}
int main(int argc, char** argv)
{
_onexit(exitFunc);
unsigned short port; /* port server binds to */
char buff[BUFF_SIZE]; /* buffer for sending & receiving data */
struct sockaddr_in client; /* client address information */
struct sockaddr_in server; /* server address information */
int namelen; /* length of client name */
const char* filePath = new char[FILE_NAME_LENGTH];
port = 5010;
filePath = "D:\\PT\\bet.mkv"; //这里自行选择
long long int fileSize = getFileSize(filePath);
printf("fileSize:%lld\n", fileSize);
char* fileName = getFileName(filePath);
printf("fileName:%s\n", fileName);
WSADATA wsadata;
WSAStartup(0x202, &wsadata);
//创建socket服务
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("socket error\n");
exit(2);
}
//socket和服务地址绑定
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = INADDR_ANY;
if (bind(s, (struct sockaddr*)&server, sizeof(server)) < 0)
{
printf("bind error\n");
exit(3);
}
//监听服务,只允许一个客户端连接
if (listen(s, 1) != 0)
{
printf("listen error\n");
exit(4);
}
//等待连接
namelen = sizeof(client);
while (true) {
//循环 一直等待客户端的连接
if ((ns = accept(s, (struct sockaddr*)&client, &namelen)) == -1)
{
printf("accept error\n");
exit(5);
}
//有客户端连接过来之后 将指定文件发送给客户端
FILE* f;
f = fopen(filePath, "rb");
if (f == NULL) {
printf("file:%s doesn't exist\n", filePath);
exit(6);
}
long long int sendSize = 0;
//先将文件大小的数据发送给客户端
_ltoa(fileSize, buff, 10);
if (send(ns, buff, sizeof(buff), 0) < 0) {
printf("send fileSize to client error\n");
exit(7);
}
//再将文件名发送给客户端
printf("sizeof:%d strlen:%d\n", sizeof(fileName), strlen(fileName));
if (send(ns, fileName, strlen(fileName), 0) < 0) {
printf("send fileName to client error\n");
exit(7);
}
while (sendSize < fileSize) {
memset(buff, 0, 1024 * 1024);
size_t iread = fread(buff, sizeof(char), BUFF_SIZE, f);
printf("iread:%d\n", iread);
if (iread < 0) {
printf("fread error\n");
fclose(f);
break;
}
int iSend = send(ns, buff, iread, 0);
if (iSend < 0) {
printf("send error\n");
fclose(f);
break;
}
sendSize += iSend;
printf("fileSize:%lld iSend:%d sendSize:%lld\n", fileSize, iSend, sendSize);
fseek(f, sendSize, SEEK_SET);
}
fclose(f);
}
printf("Server ended successfully\n");
exit(0);
}
客户端
#include <iostream>
#include <stdio.h>
#include <WinSock2.h>
#include <time.h>
#include<string>
using namespace std;
#define BUFF_SIZE (1024 * 1024)
#define FILE_NAME_LENGTH 1024
int s; /* client socket */
int exitFunc() {
closesocket(s);
return 0;
}
int main(int argc, char** argv)
{
_onexit(exitFunc);
WSADATA wsadata;
WSAStartup(0x202, &wsadata);
printf("start...\n");
unsigned short port; //服务端口
char buf[BUFF_SIZE]; //缓存
struct hostent* hostnm; //服务地址信息
struct sockaddr_in server; //服务sockaddr信息
hostnm = gethostbyname("127.0.0.1");
if (hostnm == (struct hostent*)0)
{
fprintf(stderr, "Gethostbyname failed\n");
exit(2);
}
port = 2000;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = *((unsigned long*)hostnm->h_addr);
//创建socket
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("Socket error\n");
exit(3);
}
//准备连接服务端
printf("ready to connet to server ...\n");
if (connect(s, (struct sockaddr*)&server, sizeof(server)) < 0)
{
printf("Connect error\n");
exit(4);
}
//先接收文件大小
int iRecv = 0;
memset(buf, 0, BUFF_SIZE);
iRecv = recv(s, buf, BUFF_SIZE, 0);
if (iRecv < 0) {
printf("recv fileSize error\n");
exit(5);
}
long long int totalFileSize = atoll(buf);
printf("totalFileSize:%lld\n", totalFileSize);
//再接收文件名
memset(buf, 0, BUFF_SIZE);
iRecv = recv(s, buf, BUFF_SIZE, 0);
if (iRecv < 0) {
printf("recv fileName error\n");
exit(5);
}
char fileName[FILE_NAME_LENGTH];
memset(fileName, 0, FILE_NAME_LENGTH);
memcpy(fileName, buf, strlen(buf));
printf("recv fileName:%s\n", fileName);
//接收文件 将文件保存到指定位置
char* filePath = new char[FILE_NAME_LENGTH];
memset(filePath, 0, FILE_NAME_LENGTH);
const char* basePath = "D:\\client\\";
memcpy(filePath, basePath, strlen(basePath));
strcat(filePath, fileName);
printf("filePath:%s\n", filePath);
FILE* f = NULL;
f = fopen(filePath, "wb");
if (f == NULL) {
printf("file:%s doesn't exist and failed to create\n", filePath);
exit(5);
}
long long int fileRecv = 0;
time_t start;
start = time(NULL);
while (fileRecv < totalFileSize) {
memset(buf, 0, BUFF_SIZE);
iRecv = recv(s, buf, BUFF_SIZE, 0);
if (iRecv < 0)
{
printf("Recv error\n");
exit(6);
}
if (iRecv == 0) {
break;
}
fileRecv += iRecv;
time_t end = time(NULL);
time_t cost = end - start;
//动态计算出传输完需要用时多久
time_t totalTime = 0;
//计算出剩余时间
time_t leftTime = 0;
if (cost != 0) {
totalTime = totalFileSize / (fileRecv / cost);
leftTime = (totalFileSize - fileRecv) / (fileRecv / cost);
}
printf("totalFileSize:%lld recv file size:%lld, totalTime:%d 's, leftTime:%d 's\n", totalFileSize, fileRecv, totalTime, leftTime);
fwrite(buf, sizeof(char), iRecv, f);
}
fclose(f);
printf("Client Ended Successfully\n");
exit(0);
}
以上代码我是在vs2019里跑成的。先运行服务器端进行监听,然后运行客户端,如果连接成功,那么传输就会开始,文件路径可以自行修改