这个处理后最大可接受的文件时128k。
server:
// server1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include "pch.h" #include <iostream> #include<WinSock2.h> #include<string> #include<cstdio> #include<cstdlib> #pragma comment(lib,"ws2_32.lib") #define MAX_BUFFER 1024 using namespace std; static long int total = 0; char* getFile_Name(char filepath[]); int writeFile(char buffer[], FILE *fp); int main() { WORD sockVersion = MAKEWORD(2, 2); WSADATA wsadata; if (WSAStartup(sockVersion, &wsadata)) { printf("WSAStartup failed! \n"); return 0; } SOCKET serverSocket = socket(AF_INET, SOCK_DGRAM, 0); if (serverSocket == INVALID_SOCKET) { printf("socket failed! \n"); WSACleanup(); return -1; } sockaddr_in saddr; int slen = sizeof(saddr); sockaddr_in caddr; int clen = sizeof(caddr); saddr.sin_family = AF_INET; saddr.sin_port = htons(8899); saddr.sin_addr.S_un.S_addr = INADDR_ANY; //绑定 int nRet = bind(serverSocket, (SOCKADDR*)&saddr, slen); if (nRet == SOCKET_ERROR) { printf("bind failed! \n"); return -2; } //存放接收文件的缓冲区 char buffer[MAX_BUFFER]; int iRcv; int isend; //buffer = (char*)malloc(sizeof(char)*MAX_BUFFER); memset(buffer, 0, MAX_BUFFER); //存放文件的路径和文件名字 char filepath[100]; char filename[100]; char begin[] = "好的,我准备好了接收文件。"; char end[] = "接收完成!"; FILE *fp; memset(filename, 0, sizeof(filename)); memset(filepath, 0, sizeof(filepath)); /* 发送的包较大,超过接受者缓存导致丢包: 包超过mtu size数倍,几个大的udp包可能会超过接收者的缓冲,导致丢包。 这种情况可以设置socket接收缓冲。 */ int nRecvBuf = 128 * 1024;//设置为128K setsockopt(serverSocket, SOL_SOCKET, SO_RCVBUF, (const char*)&nRecvBuf, sizeof(int)); while (1) { cout << "=============================================Server==============================================" << endl; //接收对方的准备发信息前的声明 iRcv = recvfrom(serverSocket, filepath , sizeof(filepath), 0, (SOCKADDR*)&caddr, &clen); if (iRcv == SOCKET_ERROR) { cout << "接收客户端信息出错!" << endl; closesocket(serverSocket); WSACleanup(); Sleep(2000); return 0; } cout << "++client: " << filepath << endl; memset(filepath, 0, sizeof(filepath)); //发送准备好的信息 isend = sendto(serverSocket, begin, strlen(begin), 0, (SOCKADDR*)&caddr, clen); if (isend == SOCKET_ERROR) { cout << "发送信息出错!" << endl; closesocket(serverSocket); WSACleanup(); Sleep(2000); return 0; } cout << "==server: " << begin << endl; //接收文件名的全路径 iRcv = recvfrom(serverSocket, filepath, sizeof(filepath), 0, (SOCKADDR*)&caddr, &clen); if (iRcv == SOCKET_ERROR) { cout << "接收文件路径信息出错!" << endl; closesocket(serverSocket); WSACleanup(); Sleep(2000); return 0; } //处理文件全路径名,分离出文件名 char *file_name = getFile_Name(filepath); strcpy_s(filename, file_name); memset(filepath, 0, sizeof(filepath)); //以附加方式打开可读 / 写的文件。若文件不存在,则会建立该文件,如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(原来的 EOF 符不保留)。 fp = fopen(filename, "a+"); if (fp != NULL) { cout << "准备接收文件······" << endl; cout << "文件内容为:" << endl; while (1) { //接收文件内容并计算接收的字节数 iRcv = recvfrom(serverSocket, buffer, sizeof(buffer), 0, (SOCKADDR*)&caddr, &clen); if (iRcv == SOCKET_ERROR) { cout << "文件接收出错!" << endl; closesocket(serverSocket); WSACleanup(); Sleep(2000); return 0; } //调用写文件函数,将接收内容写入文件,当读取对方发送的文件结束符时不在写入文件 int f = writeFile(buffer,fp); memset(buffer, 0, MAX_BUFFER); if (f == 1) break; } //向客服端说明自己接收 isend = sendto(serverSocket, end, strlen(end), 0, (SOCKADDR*)&caddr, clen); if (isend == SOCKET_ERROR) { cout << "发送信息出错!" << endl; closesocket(serverSocket); WSACleanup(); Sleep(2000); return 0; } cout << "==server: " << end << endl; } else { cout << "打开文件失败!" << endl; } fclose(fp); fp = NULL; } closesocket(serverSocket); WSACleanup(); return 0; } //用于分离出用户发送文件的文件名,并提供完整路径,生成文件存储路径 char* getFile_Name(char filepath[]) { //用于记录文件名字的长度 int count = 0; //文件路径的原长度 int len = strlen(filepath); //cout << len << endl; //从名字最后往前遍历,遍历到"\"时停止遍历,此时的count数为文件名字的总长度 for (int i = len; i > 0; i--) { //没遇到“\"就说明文件名没有结束,执行count+1; if (filepath[i] != '\\') { count++; } //否则,说明文件名结束,再往前是子目录,停止遍历 else { break; } } //cout << "count==" << count << endl; //文件名字在目录中的第一个位置 int pos = len - count + 1; //cout << "pos=" << pos << endl; //文件名的位置 int j = 0; //存文件名 char name[20]; //初始化 memset(name, 0, sizeof(name)); //开始将文件名存在数组中 for (unsigned int i = pos; i < (strlen(filepath)); i++) { //cout << i << " "; name[j] = filepath[i]; //cout<<j<<"="<<name[j]<<" "; j++; } //cout << "len_name" << strlen(name) << endl; //for (int i = 0; i < strlen(name); i++){ //cout << name[i]; //} //cout << endl; //存放用户输入的路径 char dir[20]; cout << "请输入您存放接收文件的绝对路径:(例如:D:\\test\\)" << endl; //输入接收文件的路径 cin >> dir; // (int o = 0; o < strlen(dir); o++) { // cout << dir[o]; //} //cout << endl; //接收文件存放的目录长度 int dlen = strlen(dir); //接收文件的名字长度 int nlen = strlen(name); //cout << "dlen"<< dlen << endl; //cout << "nlen" << nlen << endl; //存放接收文件的全路径 char file_name[100]; memset(file_name, 0, sizeof(file_name)); int k = 0; //先把目录拷贝到接收文件全路径数组里 for (k = 0; k < dlen; k++) { file_name[k] = dir[k]; } //再把文件名字拷贝到接收文件全路径数组里 for (int i = 0; i < nlen; i++) { file_name[k] = name[i]; k++; } cout << "文件存储路径为:"; for (unsigned int o = 0; o < (strlen(file_name)); o++) { cout << file_name[o]; } cout << endl; return file_name; } int writeFile(char buffer[],FILE *fp ) { int flag = 0; string data = ""; data = buffer; //寻找结束符号 int goal = data.rfind("success transport"); //若找不到结束符,则将数据写入文件 if (goal == -1) { fwrite(buffer, strlen(buffer), 1,fp); total += strlen(buffer); //指针当前位于文件末尾 fseek(fp, 0, 2); cout << buffer; } else { //找到结束符, cout << endl; cout << endl; cout << "++client: " << buffer << endl; flag = 1; } return flag; }
client:
// client1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include "pch.h" #include <iostream> #include<WinSock2.h> #include<string> #include<stdio.h> #include<cstdlib> #pragma comment(lib,"ws2_32.lib") #define MAX_BUFFER 120 using namespace std; int main() { long filesize(FILE*stream); WORD sockVersion = MAKEWORD(2, 2); WSADATA wsadata; if (WSAStartup(sockVersion, &wsadata)) { cout << "WSAStartup failed !" << endl; return 0; } SOCKET client; client = socket(AF_INET, SOCK_DGRAM, 0); if (client == INVALID_SOCKET) { cout << "socket failed" << endl; return 0; } sockaddr_in caddr, saddr; int slen = sizeof(saddr); int clen = sizeof(caddr); saddr.sin_family = AF_INET; saddr.sin_port = htons(8899); saddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); FILE *fp; //声明一个文件类型的指针 int isend; //文件发送成功状态 int ircv; char buffer[MAX_BUFFER]; //文件的缓冲区 char filepath[200]; char begin[]="我要准备给你发邮件了。"; // memset(buffer, 0, sizeof(buffer)); memset(filepath, 0, sizeof(filepath)); while (1) { cout << "++++++++++++++++++++++++++++++++++++Client++++++++++++++++++++++++++++++++++++++++++++" << endl; //给服务器发送文件前的呼叫 isend = sendto(client, begin, strlen(begin), 0, (SOCKADDR*)&saddr, slen); cout << "++client: " << begin << endl; //接收服务器端准备信息 ircv = recvfrom(client, filepath, sizeof(filepath), 0, (SOCKADDR*)&saddr, &slen); if (ircv==SOCKET_ERROR) { cout << " 服务器关闭状态,无法访问!" << endl; closesocket(client); WSACleanup(); cout << " 2s后将退出此控制台!" << endl; Sleep(2000); return 0; } cout << "==server: " << filepath << endl; memset(filepath, 0, sizeof(filepath)); cout << "++client: 请输入所要传送文件的路径:形如(D:\\1.txt" << endl; scanf("%s", filepath); fp = fopen(filepath, "r"); if (fp == NULL) { cout << " 文件不存在!" << endl; return 0; } else { cout << " 文件已经打开,等待传输······" << endl; Sleep(10); } isend = sendto(client, filepath, strlen(filepath), 0, (SOCKADDR*)&saddr, slen); memset(filepath, 0, sizeof(filepath)); if (isend == SOCKET_ERROR) { cout << "文件名字发送失败!" << endl; return 0; } else { cout << " ······" << endl; } //开始读取文件内容进行发送 while (!feof(fp)) { memset(buffer, 0, sizeof(buffer)); fread(buffer, 1, MAX_BUFFER, fp); isend = sendto(client, buffer, sizeof(buffer), 0, (SOCKADDR*)&saddr, slen); if (isend == SOCKET_ERROR) { cout << " 文件传输失败!" << endl; closesocket(client); WSACleanup(); cout << " 2s后将退出此控制台!" << endl; Sleep(2000); return 0; } } //告诉服务器传送此文件结束。 isend = sendto(client, "success transport", strlen("success transport"), 0, (SOCKADDR*)&saddr, slen); if (isend == SOCKET_ERROR) { cout << " 结束信息传输失败!" << endl; closesocket(client); WSACleanup(); cout << " 2s后将退出此控制台!" << endl; Sleep(2000); return 0; } cout << "++client: success transport "<< endl; //接收服务器接收文件的确认信息 ircv = recvfrom(client, filepath, sizeof(filepath), 0, (SOCKADDR*)&saddr, &slen); if (ircv == SOCKET_ERROR) { cout << " 接收服务器确认信息失败!" << endl; closesocket(client); WSACleanup(); cout << " 2s后将退出此控制台!" << endl; Sleep(2000); return 0; } cout << "==server: " << filepath << endl; memset(buffer, 0, sizeof(buffer)); cout << endl; fclose(fp); fp = NULL; } /* while (1) { //获取文件剩余长度 long int length=filesize(fp); cout << "当前文件未读:" << length << endl; //文件剩余长度大于缓冲区大小,进行分块地区 if (length > sizeof(buffer)) { memset(buffer, 0, sizeof(buffer)); fread(buffer, 1, MAX_BUFFER, fp); isend = sendto(client, buffer, strlen(buffer), 0, (SOCKADDR*)&saddr, slen); if (isend == SOCKET_ERROR) { cout << "文件传输失败!" << endl; closesocket(client); WSACleanup(); return 0; } } else { //进行最后一次文件的读取 memset(buffer, 0, sizeof(buffer)); fread(buffer, 1, MAX_BUFFER, fp); isend = sendto(client, buffer, strlen(buffer), 0, (SOCKADDR*)&saddr, slen); if (isend == SOCKET_ERROR) { cout << "文件传输失败!" << endl; closesocket(client); WSACleanup(); return 0; } //告诉服务器传送此文件结束。 isend = sendto(client, "success transport", strlen("success transport"), 0, (SOCKADDR*)&saddr, slen); cout << "文件读取完毕!" << endl; break; } } fclose(fp); fp = NULL; }*/ closesocket(client); WSACleanup(); return 0; } long filesize(FILE*stream) { long curpos, length; curpos = ftell(stream); //获取当前读写位置偏离文件头部的字节数。 fseek(stream, 0L, SEEK_END); //重新定位到文件的末尾位置 length = ftell(stream); //获取当前读写位置(当前指针在末尾)偏离文件头部的字节数,即文件总长度 fseek(stream, curpos, SEEK_SET); //从文件头部正向偏离curpos个位置,即回到原来的位置 return length-curpos; //获取文件剩余未读长度 }
问题: 最大的问题就是乱码问题,在接收文件的过程中总是会出现乱码问题,查了很多,乱七八糟的,由于经验少,想不到问题出现在哪里,最后发现是缓冲区问题。出现了数据的丢包等问题应该。