上一次解决编码问题,这里解决成帧问题。
在成帧的问题上,有很多需要解决的问题。首要的一点是:如何来定义数据的开头和结尾。
因为实验原因,这里采用最简单的方式:在数据的开头的结尾加入字节流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