c - UDP 传输 - 实现 CRC-16

标签 c udp crc crc16

我是 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()函数,调用crc16() createBuffer() 内的函数函数并获取它返回的值并将其分配给参数值,然后将其附加到缓冲区?

或者有没有一种我目前没有考虑的更简单的方法?

最佳答案

关于实现我这里的 CRC-16 功能的最佳/最简单方法是什么?

首先,您的 CRC-16 函数似乎已经实现。下面说明如何使用它。

CRC 函数通常用于将任意大小的文件或缓冲区作为输入,并生成一个唯一值以验证文件内容。

这是一个简单的示例,说明如何使用此函数读取两种类型的输入...(注意,bufInbuf 可以是多种类型的数组更大的尺寸)

int main(void)
{
    unsigned char bufIn[] = {1,45,76,23,245,9,54,55,210,90,23,54,78,14,27,86,34};
    char buf[] = {"lkjahsloiwuyhfajsldnaouiyhrqkuhsldajnfdlakdsfa;jsidurfaliu;adjklflkja;sdlkjasdklfauiea;e"};

    unsigned short crcOut1, crcOut2;

    crcOut1 = crc16(bufIn, sizeof(bufIn));   //for bufIn returns 0x7782
    crcOut2 = crc16(buf, sizeof(buf));       //for buf returns   0x98FB

    return 0;
}

编辑以解决评论中的问题...

在您的代码中,使用此功能的一种可能方法是在 fread while 循环 中调用 crc16() 函数:

unsigned short packetCrc;

while ((n = fread(dataContent, 1, DATA_LEN - 1,fp)) > 0) // read data of the file
{
    packetCrc = crc16(dataContent, n);
    // verify packetCrc value against some expected value perhaps?
    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
}

关于c - UDP 传输 - 实现 CRC-16,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50042937/

相关文章:

c++ - C和C++中带有序列点和UB的差异

c - 为什么这两个函数不将十进制转换为二进制(uint8_t)?

sockets - UDP SetWriteBuffer 和 SetReadBuffer 如何处理操作系统的缓冲区?

php - PHP 中的 CRC8 校验

error-handling - BSD校正可能吗?

c - 使用 fwrite() 写入某些字节时出错

c - 逻辑否定如何在 C 中工作?

java - 监控 Windows Server、Java 中的 UDP 数据包丢失

c - 音频数据包类型

java - CRC 校验和迭代 Java