上一次解决编码问题,这里解决成帧问题。
在成帧的问题上,有很多需要解决的问题。首要的一点是:如何来定义数据的开头和结尾。
因为实验原因,这里采用最简单的方式:在数据的开头的结尾加入字节流01111110,在正式的数据内容中,凡是出现5个1,就在后面补一个0.
第一个难点:如何进行流量的控制?
这里同样采用最简单的停等协议。将帧按照0~7进行编号,在帧的前3位记录帧的编号。发送方发送第一个帧后,等待接收方的响应。如果超时,则重发。接收方收到消息后,发送需要的下帧的编号,如果超时没有得到响应,则重发。在确认第一帧发送完成后,发送方以后发送的内容只有得到确认才继续发送。
第二个难点:检错码
这里使用经常使用的CRC校验码。
实验本来不要求使用完全的程序控制。因此,我使用小程序完成专门的任务,然后使用bat或者shell脚本将小工具链接起来,达到智能的目的。
第一个是CRC的实现。我将常用的命令写到CRC.h的头文件中。
// CRC.h
#ifndef CRC_H
#define CRC_H
#define G_LENGTH 5
#include <stdio.h>
static short G[G_LENGTH] = {1, 0, 0, 1, 1};
short* getRemainder(short* frame, int length);
int getFileLength(FILE *fp);
#endif
// CRC.c
#include <stdio.h>
#include "CRC.h"
#include <malloc.h>
short* getRemainder(short* frame, int length)
{
int i, j, k;
short step[G_LENGTH];
short* remainder;
remainder = (short*)malloc(sizeof(short) * (G_LENGTH - 1));
for (i = 0; i < G_LENGTH; i++)
step[i] = frame[i];
for (i = 0; i < length - G_LENGTH + 1; i++)
{
if (step[0] == 0)
{
for (j = 0; j < 4; j++)
{
step[j] = step[j + 1] ^ 0;
}
}
else if (step[0] == 1)
for (j = 0; j < 4; j++)
step[j] = step[j + 1] ^ G[j + 1];
if (i < length - G_LENGTH)
step[4] = frame[i + 5];
}
for (i = 0; i < 4; i++)
remainder[i] = step[i];
return remainder;
}
int getFileLength(FILE *fp)
{
int length;
if (fp == NULL)
return -1;
fseek(fp, 0L, SEEK_END);
length = ftell(fp);
fseek(fp, 0L, SEEK_SET);
return length;
}
// addCRC.c
#include "CRC.h"
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
FILE* frameFile;
FILE* writeFrame;
int length = 0;
int i = 0;
short* frame;
short* add;
char c;
if ((frameFile = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "Cannot open %s!\n", argv[1]);
exit(EXIT_FAILURE);
}
length = getFileLength(frameFile);
frame = (short*)malloc(sizeof(short) * (length + G_LENGTH - 1));
while ((c = getc(frameFile)) != EOF)
{
if (c == ‘0‘)
frame[i++] = 0;
else if (c == ‘1‘)
frame[i++] = 1;
else
{
fprintf(stderr, "Illegal character!\n");
free(frame);
fclose(frameFile);
exit(EXIT_FAILURE);
}
}
for (i = 0; i < G_LENGTH; i++)
frame[length + i] = 0;
add = getRemainder(frame, length + G_LENGTH - 1);
fclose(frameFile);
for (i = 0; i < G_LENGTH - 1; i++)
frame[length + i] = add[i];
if ((writeFrame = fopen(argv[1], "w")) == NULL)
{
fprintf(stderr, "Cannot open frame.txt!\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < length + G_LENGTH - 1; i++)
if (frame[i] == 0)
fprintf(writeFrame, "0");
else
fprintf(writeFrame, "1");
fclose(writeFrame);
free(frame);
free(add);
return 0;
}addflag.c用于添加开始和结尾的标记以及5个1后面加0:
// addflag.c
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "CRC.h"
void addFlag(FILE *fp);
int main(int argc, char* argv[])
{
FILE *frameFile;
short* frame;
int i;
char c;
int numOfOne, len;
if ((frameFile = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "Cannot open file %s\n", argv[1]);
exit(EXIT_FAILURE);
}
len = getFileLength(frameFile);
frame = (short*)malloc(sizeof(short) * len);
i = 0;
while ((c = getc(frameFile)) != EOF)
{
if (c == ‘1‘)
frame[i++] = 1;
else if (c == ‘0‘)
frame[i++] = 0;
else
{
fprintf(stderr, "Illegal character!\n");
fclose(frameFile);
free(frame);
exit(EXIT_FAILURE);
}
}
fclose(frameFile);
if ((frameFile = fopen(argv[1], "w")) == NULL)
{
fprintf(stderr, "Cannot open file %s\n", argv[1]);
exit(EXIT_FAILURE);
}
addFlag(frameFile);
numOfOne = 0;
for (i = 0; i < len; i++)
{
if (numOfOne == 5)
{
fprintf(frameFile, "0");
numOfOne = 0;
}
if (frame[i] == 1)
{
fprintf(frameFile, "1");
numOfOne++;
}
if (frame[i] == 0)
{
fprintf(frameFile, "0");
numOfOne = 0;
}
}
addFlag(frameFile);
fclose(frameFile);
free(frame);
return 0;
}
void addFlag(FILE *fp)
{
int i;
fprintf(fp, "0");
for (i = 0; i < 6; i++)
fprintf(fp, "1");
fprintf(fp, "0");
}
pick.c用于挑选指定的内容到帧,并添加编号:
// pick.c
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include "CRC.h"
#define FRAME_LEN 32
int main(int argc, char* argv[])
{
FILE* outFile;
FILE* frameFile;
int numOfFrame;
short* frame;
char c;
int frameLength;
int i;
if (argc != 2)
{
printf("Usage: makeframe numOfFrame\n");
exit(0);
}
numOfFrame = atoi(argv[1]);
if ((outFile = fopen("out.txt", "r")) == NULL)
{
fprintf(stderr, "Cannot open file: out.txt\n");
exit(EXIT_FAILURE);
}
frame = (short*)malloc(sizeof(short) * FRAME_LEN);
frameLength = 0;
fseek(outFile, numOfFrame * FRAME_LEN, SEEK_SET);
while ((c = getc(outFile)) != EOF && frameLength < FRAME_LEN)
{
if (c == ‘1‘)
frame[frameLength++] = 1;
else if (c == ‘0‘)
frame[frameLength++] = 0;
else
{
fprintf(stderr, "Illegal character!\n");
fclose(outFile);
fclose(frameFile);
free(frame);
exit(EXIT_FAILURE);
}
}
if (c == EOF)
printf("End of the file!\n");
fclose(outFile);
if ((frameFile = fopen("frame.txt", "w")) == NULL)
{
fprintf(stderr, "Cannot open file: frame.txt\n");
exit(EXIT_FAILURE);
}
for (i = 2; i >= 0; i--)
{
if (numOfFrame & (1 << i))
fprintf(outFile, "1");
else
fprintf(outFile, "0");
}
for (i = 0; i < frameLength; i++)
fprintf(frameFile, "%d", frame[i]);
fclose(frameFile);
free(frame);
return 0;
}
removeflag.c用于在数据流中找到帧,并去除标记,且去除5个1后面的0:
// removeflag.c
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "CRC.h"
static char* flag = "01111110";
void moveToFlag(FILE *fp);
int isFlag(FILE *fp);
int main(int argc, char* argv[])
{
FILE* frameFile;
int len;
short* frame;
int numOfOne = 0;
int realLen = 0, i = 0;
char c;
if ((frameFile = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "Cannot open file %s\n", argv[1]);
exit(EXIT_FAILURE);
}
len = getFileLength(frameFile);
frame = (short*)malloc(sizeof(short) * len);
moveToFlag(frameFile);
while ((c = getc(frameFile)) != EOF)
{
if (c == ‘1‘)
{
frame[i++] = 1;
numOfOne++;
}
else if (c == ‘0‘)
{
frame[i++] = 0;
numOfOne = 0;
}
else
{
fprintf(stderr, "Illegal character!\n");
fclose(frameFile);
free(frame);
exit(EXIT_FAILURE);
}
realLen++;
if (numOfOne >= 5)
{
c = getc(frameFile);
if (c == ‘1‘)
{
printf("Appears 6 one, Illegal!\n");
fclose(frameFile);
free(frame);
exit(0);
}
else if (c == ‘0‘)
numOfOne = 0;
else
{
fprintf(stderr, "Illegal character!\n");
fclose(frameFile);
free(frame);
exit(EXIT_FAILURE);
}
}
if (isFlag(frameFile))
break;
}
fclose(frameFile);
if ((frameFile = fopen(argv[1], "w")) == NULL)
{
fprintf(stderr, "Cannot open file %s\n", argv[1]);
exit(EXIT_FAILURE);
}
for (i = 0; i < realLen; i++)
{
if (frame[i] == 1)
fprintf(frameFile, "1");
else if (frame[i] == 0)
fprintf(frameFile, "0");
}
fclose(frameFile);
free(frame);
return 0;
}
int isFlag(FILE *fp)
{
int i;
char c;
c = getc(fp);
if (c == EOF)
{
printf("Cannot find flag!\n");
exit(0);
}
if (c != ‘0‘)
{
fseek(fp, -1, SEEK_CUR);
return 0;
}
for (i = 0; i < 6; i++)
{
c = getc(fp);
if (c != ‘1‘)
break;
}
if (i < 6)
{
fseek(fp, -i - 2, SEEK_CUR);
return 0;
}
fseek(fp, -7, SEEK_CUR);
return 1;
}
void moveToFlag(FILE *fp)
{
char c;
while (!isFlag(fp))
{
c = getc(fp);
if (c == EOF)
{
printf("Cannot find flag!");
exit(0);
}
}
fseek(fp, 8, SEEK_CUR);
}
checkcrc.c用于检查帧的错误并生成相应的ack内容:
// checkcrc.c
#include "CRC.h"
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
FILE* frameFile;
FILE* ackFile;
short* frame;
int length;
int i, j;
char c, temp;
short* remainder;
if ((frameFile = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "Cannot open file %s!\n", argv[1]);
exit(EXIT_FAILURE);
}
if ((ackFile = fopen("ack.txt", "w")) == NULL)
{
fprintf(stderr, "Cannot open file ack.txt!\n");
exit(EXIT_FAILURE);
}
length = getFileLength(frameFile);
frame = (short*)malloc(sizeof(short) * length);
i = 0;
while ((c = getc(frameFile)) != EOF)
{
if (c == ‘0‘)
frame[i++] = 0;
else if (c == ‘1‘)
frame[i++] = 1;
else
{
fprintf(stderr, "Illegal character!\n");
fclose(frameFile);
free(frame);
exit(EXIT_FAILURE);
}
}
remainder = getRemainder(frame, length);
for (i = 0; i < G_LENGTH - 1; i++)
if (remainder[i] != 0)
break;
fseek(frameFile, 0, SEEK_SET);
c = 0;
for (j = 2; j >= 0; j--)
{
if (getc(frameFile) == ‘1‘)
{
c |= (1 << j);
}
}
if (i == G_LENGTH - 1)
{
printf("Yes, you get right frame!\n");
c++;
}
else
printf("No, you get a wrong frame!\n");
for (i = 2; i >= 0; i--)
{
temp = c & (1 << i) ? 1 : 0;
for (j = 0; j < 5; j++)
fprintf(ackFile, "%d", temp);
}
fclose(frameFile);
free(frame);
free(remainder);
return 0;
}
将以上程序组合:
1、makeframe.bat用于生成帧,
@echo off if "%1" == "" (echo 请输入帧号! echo 用法:makeframe 帧号 goto A) pick %1 addcrc frame.txt addflag frame.txt notepad frame.txt :A2、getframe.bat用于接收帧并生成ack,
@echo off removeflag frame.txt checkcrc frame.txt notepad ack.txt
计通网实验的准备工作(2):成帧实现(C语言),布布扣,bubuko.com
原文:http://blog.csdn.net/pdcxs007/article/details/22929609