【发布时间】:2020-03-24 13:37:29
【问题描述】:
我正在尝试在 C++ 中通过 UDP 协议实现文件传输。 我所拥有的是可以发送客户端请求的文件的服务器,但它仅适用于 .txt 文件。当我尝试对图像或可执行文件执行相同操作时,传输损坏并且文件大约为 0 KB。
服务器:
#include <winsock2.h>
#include <stdio.h>
#include <iostream>
#include <sstream>
#pragma comment(lib, "ws2_32.lib")
#define cipherKey 'S'
int const bufferSize = 512;
char buffer[bufferSize];
void clearBuf(char* b)
{
int i;
for (i = 0; i < bufferSize; i++)
b[i] = '\0';
}
char* notFound = "File not found.";
char Cipher(char ch)
{
return ch ^ cipherKey;
}
int sendFile(FILE* file, char* buffer, int s)
{
int i, len;
if (file == NULL)
{
strcpy(buffer, notFound);
len = strlen(notFound);
buffer[len] = EOF;
return 1;
}
char ch, ch2;
for (i = 0; i < s; i++)
{
ch = fgetc(file);
ch2 = Cipher(ch);
buffer[i] = ch2;
if (ch == EOF)
return 1;
}
return 0;
}
int main()
{
WSADATA wsaData;
int wynik_winsock = WSAStartup(MAKEWORD(2,2), &wsaData);
if(wynik_winsock != 0)
{
exit(1);
}
SOCKET socketServer;
socketServer = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(socketServer == INVALID_SOCKET)
{
WSACleanup();
exit(1);
}
char* ipAdd = "127.0.0.1";
int port = 1234;
SOCKADDR_IN server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ipAdd);
if(bind(socketServer, (SOCKADDR *)&server, sizeof(server)) == SOCKET_ERROR)
{
closesocket(socketServer);
WSACleanup();
exit(1);
}
std::cout << "Waiting." << std::endl;
SOCKADDR_IN client;
int len_client = sizeof(client);
FILE* file;
if(recvfrom(socketServer, buffer, bufferSize, 0, (SOCKADDR *)&client, &len_client) == SOCKET_ERROR) //Odbiór danych od clienta wraz z kontrolą błędów.
{
closesocket(socketServer);
WSACleanup();
exit(1);
}
else
{
file = fopen(buffer, "rb");
std::cout << "Filename: " << buffer << std::endl;
if(file == NULL)
{
std::cout << "Couldnt open a file." << std::endl;
}
else
{
while (true)
{
if(sendFile(file, buffer, bufferSize))
{
sendto(socketServer, buffer, bufferSize, 0, (SOCKADDR *)&client, len_client);
break;
}
sendto(socketServer, buffer, bufferSize, 0, (SOCKADDR *)&client, len_client);
clearBuf(buffer);
}
fclose(file);
}
}
closesocket(socketServer);
WSACleanup();
system("pause");
return 0;
}
客户:
#include <winsock2.h>
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <string.h>
#pragma comment(lib, "ws2_32.lib")
#define cipherKey 'S'
int const bufferSize = 512;
char buffer[bufferSize];
void clearBuf(char* b)
{
int i;
for (i = 0; i < bufferSize; i++)
b[i] = '\0';
}
char Cipher(char ch)
{
return ch ^ cipherKey;
}
int recvFile(char* buffer, int s, FILE* file)
{
int i;
char ch;
for (i = 0; i < s; i++)
{
ch = buffer[i];
ch = Cipher(ch);
if (ch == EOF)
{
return 1;
}
else
{
fprintf(file, "%c", ch);
}
}
return 0;
}
int main()
{
WSADATA wsaData;
int wynik_winsock = WSAStartup(MAKEWORD(2,2), &wsaData);
if(wynik_winsock != 0)
{
exit(1);
}
SOCKET socketClient;
socketClient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(socketClient == INVALID_SOCKET)
{
WSACleanup();
exit(1);
}
char* ipAdd = "127.0.0.1";
int port = 1234;
SOCKADDR_IN server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ipAdd);
int serverSizeOf = sizeof(server);
std::cout << "Name of file to send: ";
std::cin >> buffer;
if(sendto(socketClient, buffer, bufferSize, 0, (SOCKADDR *)&server, serverSizeOf) == SOCKET_ERROR)
{
closesocket(socketClient);
WSACleanup();
exit(1);
}
FILE* file;
file = fopen(buffer, "ab");
while (true)
{
clearBuf(buffer);
if(recvfrom(socketClient, buffer, bufferSize, 0, (SOCKADDR *)&server, &serverSizeOf) == SOCKET_ERROR)
{
closesocket(socketClient);
WSACleanup();
exit(1);
}
if (recvFile(buffer, bufferSize, file))
{
break;
}
fclose(file);
}
closesocket(socketClient);
WSACleanup();
system("pause");
return 0;
}
为了完成我上面所说的,我使用了教程:C program for file Transfer using UDP (Linux)。 如何调整代码以仅发送 .txt 以外的其他文件?提前谢谢你。
【问题讨论】:
-
fgetc函数返回int。这实际上对于与EOF的比较非常重要。 -
另外,如果您传输的文件不是是
bufferSize的倍数会怎样? -
@Someprogrammerdude 对于 2B 和 258B 文本文件,它工作得很好。
-
另外,如果 UDP 包乱序到达客户端会发生什么?如果数据包丢失会怎样?使用 TCP 将文件传输到单个目标。
-
@TedLyngmo 由于我们讲师的指导,我必须使用 UDP。