【发布时间】:2018-04-26 12:24:12
【问题描述】:
我是 C 语言的新手,我的任务是我必须在给定的 UDP 文件传输解决方案中实现 CRC-16。给定代码如下:
#pragma comment(lib, "ws2_32.lib")
#include "stdafx.h"
#include <winsock2.h>
#include "ws2tcpip.h"
#include <stdio.h>
#define TARGET_IP "10.4.115.122"
//#define TARGET_IP "127.0.0.1"
#define BUFFERS_LEN 1024
#define SIZE_PACKET 10 // we can send up to 9 999 999 999 packets
#define HEADER_LEN (SIZE_PACKET + 5)
#define DATA_LEN (BUFFERS_LEN - HEADER_LEN)
//#define SENDER
#define END {getchar();return 0;}
#define RECEIVER
typedef struct Data
{
int size;
char *data;
}Data;
#ifdef SENDER
#define TARGET_PORT 5005
#define LOCAL_PORT 8888
#endif // SENDER
#ifdef RECEIVER
#define TARGET_PORT 8888
#define LOCAL_PORT 5005
#endif // RECEIVER
void InitWinsock()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
}
void print(char *data, int size)
{
for (int i = 0; i < size; i++)
{
if (data[i] == '\0')
{
printf("\\0");
}
else
{
printf("%c", data[i]);
}
}
printf("\n");
}
void clearBuffer(char *buffer, int size)
{
/* Put NULL character on the array */
for (int i = 0; i < size; i++)
{
buffer[i] = '\0';
}
}
void createHeaderBuffers(char *buffer, int info, int size)
{
// create the array containing the number of the packet and the data length
char temp[HEADER_LEN];
clearBuffer(temp, HEADER_LEN);
sprintf(temp, "%d", info);
int size_temp = strlen(temp);
int begin = size - size_temp;
for (int i = 0; i < size; i++)
{
if (i < begin) // fill the begining of the array with zero
{
buffer[i] = '0';
}
else // add the usefull info at the end e.g : 0000052
{
buffer[i] = temp[i - begin];
}
}
}
int createBuffer( char *buffer, char *data,int numPacket,int dataLength)
{
/* Create the buffer we will send*/
char numPacket_c[SIZE_PACKET+1];
char dataLength_c[5];
clearBuffer(buffer, BUFFERS_LEN);
clearBuffer(numPacket_c, 4);
clearBuffer(dataLength_c, 5);
createHeaderBuffers(numPacket_c, numPacket, SIZE_PACKET); // create the array containing the number of the packet
createHeaderBuffers(dataLength_c, dataLength, 4); // create the array containing the length of the data
for (int i = 0; i < BUFFERS_LEN; i++)
{
char ch;
if (i < SIZE_PACKET) // start by adding the number of the packet byte by byte
{
buffer[i] = numPacket_c[i];
}
else if (i < SIZE_PACKET+4) // then we add the length of the data
{
buffer[i] = dataLength_c[i- SIZE_PACKET];
}
else if (i < HEADER_LEN) // the the flag to say if it(s the end of the file
{
if(dataLength < DATA_LEN -1)
buffer[i] = '1';
else
buffer[i] = '0';
}
else if (i < HEADER_LEN + dataLength) // the the data
{
buffer[i] = data[i - HEADER_LEN];
}
else // fill the rest of the buffer with NULL character
{
buffer[i] = '\0';
}
}
return 0;
}
void copy(char *dest, char *source, int size)
{
/* Copy a buffer in another one byte by byte */
//printf("%s\n", source);
for (int i = 0; i < size; i++)
{
dest[i] = source[i];
//printf("%c\n", source[i]);
}
}
void readFile(char *buffer, int size, char *data, int *numPacket, int *dataLength, int *isEnd)
{
//print(buffer, size);
char isEnd_c[2];
char numPacket_c[SIZE_PACKET + 1];
char dataLength_c[5];
clearBuffer(isEnd_c, 2);
clearBuffer(numPacket_c, SIZE_PACKET + 1);
clearBuffer(dataLength_c, 5);
clearBuffer(data, DATA_LEN + 1);
for (int i = 0; i < size; i++)
{
if (i < SIZE_PACKET) // read the number of the packet
{
numPacket_c[i] = buffer[i];
printf("%c", buffer[i]);
}
else if (i < SIZE_PACKET + 4) // read the length of the data
{
dataLength_c[i - SIZE_PACKET] = buffer[i];
}
else if (i < HEADER_LEN) // read the isEnd FLAG
{
printf("\n%c\n", buffer[i]);
isEnd_c[0] = buffer[i];
}
else // read the data
{
data[i - HEADER_LEN] = buffer[i];
}
}
*numPacket = atoi(numPacket_c);
*isEnd = atoi(isEnd_c);
*dataLength = atoi(dataLength_c);
printf("%d ; %d ; %d\n", *numPacket, *dataLength, *isEnd);
}
unsigned short crc16(const unsigned char* numPacket, unsigned char length) {
unsigned char x;
unsigned short crc = 0xFFFF;
while (length--) {
x = crc >> 8 ^ *numPacket++;
x ^= x >> 4;
crc = (crc << 8) ^ ((unsigned short)(x << 12)) ^ ((unsigned short)(x << 5)) ^ ((unsigned short)x);
}
return crc;
}
//**********************************************************************
int main()
{
SOCKET socketS;
InitWinsock();
struct sockaddr_in local;
struct sockaddr_in from;
int fromlen = sizeof(from);
local.sin_family = AF_INET;
local.sin_port = htons(LOCAL_PORT);
local.sin_addr.s_addr = INADDR_ANY;
socketS = socket(AF_INET, SOCK_DGRAM, 0);
if (bind(socketS, (sockaddr*)&local, sizeof(local)) != 0) {
printf("Binding error!\n");
getchar(); //wait for press Enter
return 1;
}
//**********************************************************************
#ifdef SENDER
FILE *fp, *fp1;
char buffer_tx[BUFFERS_LEN];
int numPacket = 0;
char numberPacket[BUFFERS_LEN];
int isEnd = 0;
char test[100];
char header[HEADER_LEN];
char data[DATA_LEN];
char dataContent[DATA_LEN];
int len;
int num;
char *token;
sockaddr_in addrDest;
addrDest.sin_family = AF_INET;
addrDest.sin_port = htons(TARGET_PORT);
InetPton(AF_INET, _T(TARGET_IP), &addrDest.sin_addr.s_addr);
char *name = "test.jpg";
fp = fopen(name, "rb");
if (fp == NULL)
{
printf("error opening file\n");
}
fseek(fp, 0L, SEEK_END);
int sz = ftell(fp);
rewind(fp);
sz = (int)(sz / DATA_LEN) + 1;
strncpy(buffer_tx, name, BUFFERS_LEN); //put the nam of the file in the buffer
sendto(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send the name of the file
recvfrom(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen); // wait aknowledgment
clearBuffer(buffer_tx, BUFFERS_LEN);
sprintf(buffer_tx, "%d", sz);
sendto(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send size of file
recvfrom(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen); // wait aknowledgment
// This is to be sure that the receiver receive the name and the size correctly in the right order
clearBuffer(buffer_tx, BUFFERS_LEN);
clearBuffer(dataContent, DATA_LEN);
int n = 1;
int dataLength = 0;
while ((n = fread(dataContent, 1, DATA_LEN - 1,fp)) > 0) // read data of the file
{
clearBuffer(buffer_tx, BUFFERS_LEN); // clear the buffer for further utilisation
createBuffer(buffer_tx, dataContent, numPacket++, n); // add the header to the data |numPacket|dataLength|isEnd|data|
sendto(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send the packet
}
fclose(fp);
#endif // SENDER
#ifdef RECEIVER
FILE *fp;
char buffer_rx[BUFFERS_LEN];
Data *data;
int n = 0;
int k;
int how_many = 310;
//strncpy(buffer_rx, "12:1|salut", BUFFERS_LEN);
printf("Waiting for datagram ...\n");
int numPacket = 0;
int isEnd = 0;
int size = 0;
char size_file_c[BUFFERS_LEN];
int size_file = 0;
char header[HEADER_LEN];
char d[DATA_LEN + 1];
char name[BUFFERS_LEN];
char output[30];
char salut[DATA_LEN + 1];
sockaddr_in addrDest;
addrDest.sin_family = AF_INET;
addrDest.sin_port = htons(TARGET_PORT);
InetPton(AF_INET, _T(TARGET_IP), &addrDest.sin_addr.s_addr);
recvfrom(socketS, name, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen); // receiving name of file
sendto(socketS, name, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send aknowledgment
recvfrom(socketS, size_file_c, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen); // receiving size of file
sendto(socketS, size_file_c, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send aknowledgment
size_file = atoi(size_file_c);
// This is to be sure that the receiver receive the name and the size correctly in the right order
data = (Data *)calloc(size_file, sizeof(Data)); // allocate memory for the data
//closesocket(socketS);
//END;
//analyseBuffer(buffer_rx,d, &numPacket, &isEnd);
for (int i = 0; i < size_file; i++)
{
printf("waiting packet\n");
if ((k = recvfrom(socketS, buffer_rx, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen)) == SOCKET_ERROR) // receive a packet
{
printf("error during reception");
getchar();
return -1;
}
else
{
readFile(buffer_rx, BUFFERS_LEN, d, &numPacket, &size, &isEnd); // analyse the pacet to extract the data, the number of the packet, the data lenght and if it's the end
data[numPacket].data = (char*) calloc(size, 1); // allocate only the necessary memory
data[numPacket].size = size;
//print(d, DATA_LEN);
copy(data[numPacket].data, d, data[numPacket].size); // copy only the usefull info (without '\0')
printf("%d ; %d\n", i, size_file);
if (isEnd)
break;
clearBuffer(buffer_rx, BUFFERS_LEN); // clear the buffer for further utilisation
}
}
printf("file name : %s\n", name);
printf("enter the name of new file to be saved\n");
scanf("%s", output); // ask the user to set a file name
fp = fopen(output, "wb");
for (int i = 0; i <size_file; i++)
{
fwrite(data[i].data, data[i].size, 1, fp); // write the data to the file in the right order
}
fclose(fp); // close the file
closesocket(socketS);
#endif // RECEIVER
//**********************************************************************
getchar(); //wait for press Enter
return 0;
}
注意CRC-16函数,即:
unsigned short crc16(const unsigned char* numPacket, unsigned char length) {
unsigned char x;
unsigned short crc = 0xFFFF;
while (length--) {
x = crc >> 8 ^ *numPacket++;
x ^= x >> 4;
crc = (crc << 8) ^ ((unsigned short)(x << 12)) ^ ((unsigned short)(x << 5)) ^ ((unsigned short)x);
}
return crc;
}
我的问题是:实现 CRC-16 功能的最佳/最简单方法是什么?我是否将unsigned short crc 参数变量传递给createBuffer() 函数,在createBuffer() 函数内调用crc16() 函数并获取它返回的值并将其分配给参数值,然后将其附加到缓冲区?
或者有没有我目前没有考虑的更简单的方法?
【问题讨论】:
-
如果您认为代码工作正常,请考虑在Code Review 上以更完整的方式展示您的工作(及其单元测试)。您可能会得到一些建议,使其更高效、更易于阅读和更好地测试。在您这样做之前,请务必先阅读A guide to Code Review for Stack Overflow users,因为那里有些事情的处理方式不同 - 例如问题标题应该简单地说明代码做了什么,因为问题总是“我该如何改进?”。
-
@Pete - 我想编辑您的帖子以重新打开它。请评论答案:1)看起来您已经在工作状态下提供给您,尽管没有将校验和包含在用户数据报标题中。正确的? 2) 是否没有说您需要实现一个在消息头中包含校验和 (CRC) 的 UDP 包? 3)您的目标是仅 Windows 实现? (或者 Linux 解决方案可以吗?)包括确切的分配措辞。事实上,我对我的回答不满意。回答这些问题也会对此有所帮助。