c - C 套接字编程 - UDP 序列中的文件传输
问题描述
我正在尝试通过套接字按顺序发送一个 mp3 文件。我发送 8194 字节的 txt 文件没有问题,但是任何其他文件类型似乎都不起作用。我一次发送一个数据包,然后接收该数据包的 ACK(停止并等待),但是我还没有实现超时。我将文件保存到 receivedFiles 目录,文件长度是正确的,但我无法打开文件,它说它是空的。
服务器端代码:
printf(">>> SERVER <<<\n");
int sock;
struct sockaddr_in serverAddress;
struct sockaddr_in clientAddress;
unsigned int clientAddressLength;
int port = 5150;
int fragmentSize = 500;
if ((sock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
printf("Socket () failed\n");
exit(0);
}
memset (&serverAddress, 0, sizeof (serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = INADDR_ANY;
serverAddress.sin_port = htons (port);
if (bind (sock, (struct sockaddr *) &serverAddress, sizeof (serverAddress)) < 0) {
printf("bind() failed");
exit(0);
}
int packetsReceived = -1;
char * buffer;
char fileNameBuffer[15];
int dataLength;
while (1) {
clientAddressLength = sizeof (clientAddress);
struct header currentHeader;
memset(¤tHeader, 0, sizeof(currentHeader));
if (recvfrom (sock, ¤tHeader, sizeof (currentHeader), 0, (struct sockaddr *) &clientAddress, &clientAddressLength) == sizeof(currentHeader)) {
printf("Prijata sprava %d\n", packetsReceived);
}
if (currentHeader.sequenceNumber == packetsReceived)
{
if (currentHeader.type == 0) { // initialization, here I receive the size of the next packet, and the filename
buffer = malloc(currentHeader.length * sizeof(char) + 1); // allocating size for the next packet
bzero (buffer, currentHeader.length * sizeof(char));
if (strcmp(currentHeader.data, "NOT_FILE") != 0) // if it's a file (not just a text then save the filename)
strcpy(fileNameBuffer, currentHeader.data);
dataLength = currentHeader.length;
}
if (currentHeader.type == 1) { // this is for text only
int buff_offset = fragmentSize * currentHeader.sequenceNumber;
memcpy(&buffer[buff_offset], currentHeader.data, currentHeader.length);
printf("buffer: %s\n", buffer);
}
printf ("[+] ACK sent\n"); // sending the ACK
struct header currAck;
currAck.type = 0;
currAck.sequenceNumber = packetsReceived;
currAck.length = 0;
if (sendto(sock, &currAck, sizeof (currAck), 0,(struct sockaddr *) &clientAddress, clientAddressLength) != sizeof (currAck)) {
printf("sendto() sent a different number of bytes than expected");
exit(0);
}
if (packetsReceived == currentHeader.fragmentCount-1) {
// If it's text
if (currentHeader.type == 1)
printf("%s", buffer);
// If it's file
if (currentHeader.type == 2) {
FILE *filePointer;
char filePath[100] = "receivedFiles/";
strncat(filePath, fileNameBuffer, 100);
filePointer=fopen(filePath, "w");
if (filePointer) {
printf("File path: %s\n", filePath);
fwrite(buffer, dataLength, 1, filePointer);
}
else
printf("Nebolo mozne vytvorit subor.\n");
memset(fileNameBuffer, '\0', sizeof(fileNameBuffer));
fclose(filePointer);
}
exit(0);
}
packetsReceived++;
}
}
}
客户端:
printf(">>> CLIENT <<<\n");
int sock;
struct sockaddr_in serverAddress;
struct sockaddr_in clientAddress;
unsigned int clientAddressLength;
char * serverIP = "127.0.0.1";
int fragmentSize = 500;
int port = 5150;
memset (&serverAddress, 0, sizeof (serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = inet_addr (serverIP);
serverAddress.sin_port = htons (port);
if ((sock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
printf("Socket () failed\n");
exit(0);
}
printf("Select type\n1 - Send text\n2 - Send file\n\n");
int type;
scanf("%d", &type);
getchar();
// For text
char buffer[2049];
bzero(buffer, sizeof(buffer));
// For files
FILE * filePointer;
char fileName[] = "hello.mp3";
char fileBuffer[125000];
bzero(fileBuffer, sizeof(fileBuffer));
unsigned long int dataLength = 0;
if (type == 1) {
fgets(buffer, 2048, stdin);
// printf("%s", buffer);
dataLength = strlen(buffer);
}
else if (type == 2) {
filePointer = fopen(fileName, "r");
if (filePointer) {
fseek(filePointer, 0, SEEK_END);
dataLength= ftell(filePointer);
printf("DATALENGTH: %lu", dataLength);
fseek(filePointer, 0, SEEK_SET);
if(fread(fileBuffer, dataLength, 1, filePointer) <= 0)
{
printf("Unable to copy file into buffer or empty file.\n");
exit(1);
}
// printf("fileBuffer: %s\n", fileBuffer);
fclose(filePointer);
}
}
int fragmentCount = dataLength / fragmentSize; // here i calculate how many sequences will I need to send the packet
if (dataLength % fragmentSize)
fragmentCount++;
int buff = -1;
while (buff < fragmentCount)
{
struct header currentFragment;
memset(¤tFragment, 0, sizeof(currentFragment));
if (buff == -1) { // sending the initialization, just the size of the file and the filename
currentFragment.type = 0;
currentFragment.length = dataLength;
(type == 2) ? (strcpy(currentFragment.data, fileName)) : (strcpy(currentFragment.data, "NOT_FILE"));
}
else {
currentFragment.type = type;
int currlength;
if ((dataLength - (buff * fragmentSize)) >= fragmentSize)
currlength = fragmentSize;
else
currlength = dataLength % fragmentSize;
currentFragment.length = currlength;
if (type == 1) memcpy (currentFragment.data, buffer + ((buff) * fragmentSize), currlength);
if (type == 2) memcpy (currentFragment.data, fileBuffer + ((buff) * fragmentSize), currlength);
}
currentFragment.sequenceNumber = buff;
currentFragment.fragmentCount = fragmentCount;
sendto(sock, ¤tFragment, sizeof(currentFragment), 0, (struct sockaddr *) &serverAddress, sizeof (serverAddress));
// Packet info
printf("\n####################\n");
printf(">>> INFO <<<\n");
printf("type: %d\n", currentFragment.type);
printf("sequenceNumber: %d\n", currentFragment.sequenceNumber);
printf("fragment count: %d\n", currentFragment.fragmentCount);
printf("length: %d\n", currentFragment.length);
printf("data: %s\n", currentFragment.data);
// Get a response
clientAddressLength = sizeof (clientAddress);
struct header currentAcknowledgement;
int response = recvfrom (sock, ¤tAcknowledgement, sizeof (currentAcknowledgement) , 0, (struct sockaddr *) &clientAddress, &clientAddressLength);
if (waitForResponse(response) == 1) {
int acktype = currentAcknowledgement.type;
int ackNumber = currentAcknowledgement.sequenceNumber;
if (ackNumber == buff && acktype == 0) {
printf ("[+] ACK received");
buff++;
}
}
else
continue;
printf("\n");
}
close (sock);
exit (0);
解决方案
推荐阅读
- windows - 离线部署 NPM 文件到工件
- django - Django将未登录用户重定向到登录页面
- java - 扩展一个没有构造函数的类
- python - 如何检查我的字符串在python中是否为空
- list - 如何从 R 中的 mapply 或 Map 函数中的数据列表中选择 2 个变量?
- mysql - 无法使用 JOIN 更新特定记录
- r - drv <- dbDriver("Oracle") 在命令行 R 中工作正常,但在 RStudio Server 上不工作
- java - 面向对象编程 - 两种方式组合实践?
- c++ - 创建数组并从中检索数据时 C++ 中的未定义行为
- javascript - 文件上传对话框第一次不显示onclick