中南大学通信电子专业通信网原理课程设计.docx

上传人:b****8 文档编号:10079731 上传时间:2023-05-23 格式:DOCX 页数:18 大小:82.09KB
下载 相关 举报
中南大学通信电子专业通信网原理课程设计.docx_第1页
第1页 / 共18页
中南大学通信电子专业通信网原理课程设计.docx_第2页
第2页 / 共18页
中南大学通信电子专业通信网原理课程设计.docx_第3页
第3页 / 共18页
中南大学通信电子专业通信网原理课程设计.docx_第4页
第4页 / 共18页
中南大学通信电子专业通信网原理课程设计.docx_第5页
第5页 / 共18页
中南大学通信电子专业通信网原理课程设计.docx_第6页
第6页 / 共18页
中南大学通信电子专业通信网原理课程设计.docx_第7页
第7页 / 共18页
中南大学通信电子专业通信网原理课程设计.docx_第8页
第8页 / 共18页
中南大学通信电子专业通信网原理课程设计.docx_第9页
第9页 / 共18页
中南大学通信电子专业通信网原理课程设计.docx_第10页
第10页 / 共18页
中南大学通信电子专业通信网原理课程设计.docx_第11页
第11页 / 共18页
中南大学通信电子专业通信网原理课程设计.docx_第12页
第12页 / 共18页
中南大学通信电子专业通信网原理课程设计.docx_第13页
第13页 / 共18页
中南大学通信电子专业通信网原理课程设计.docx_第14页
第14页 / 共18页
中南大学通信电子专业通信网原理课程设计.docx_第15页
第15页 / 共18页
中南大学通信电子专业通信网原理课程设计.docx_第16页
第16页 / 共18页
中南大学通信电子专业通信网原理课程设计.docx_第17页
第17页 / 共18页
中南大学通信电子专业通信网原理课程设计.docx_第18页
第18页 / 共18页
亲,该文档总共18页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

中南大学通信电子专业通信网原理课程设计.docx

《中南大学通信电子专业通信网原理课程设计.docx》由会员分享,可在线阅读,更多相关《中南大学通信电子专业通信网原理课程设计.docx(18页珍藏版)》请在冰点文库上搜索。

中南大学通信电子专业通信网原理课程设计.docx

中南大学通信电子专业通信网原理课程设计

题目名称:

CRC-32校验通信软件设计

一、设计目标

环境要求:

Windows;信息交换内容为文本文件;WinSock通信

编码要求:

用模2除法计算CRC码,生成多项式为CRC-32

功能要求:

能在两台计算机机上运行程序,一台产生CRC码,另一台校验。

二、设计原理和方法

1.CRC简介及原理

CRC,即循环冗余校验法是一种功能较强的检测技术。

循环冗余校验法是将所传输的数据除以一个预先设定的除数,所得的余数作为冗余比特,附加在要发送数据的末尾,被称为循环冗余校验码(CRC码),这样,实际传输的数据就能够被预先设定的除数整除。

当整个数据传送到接收方后,接收方就利用同一个除数去除接收到的数据,如果余数为0,即表明数据传输正确,否则意味着数据传输出现了差错。

确定循环冗余校验码的关键在于二进制序列的除法计算上。

其规则是:

加法、减法运算都是进行异或(XOR)运算,加法不进位,减法不借位。

计算方法如下:

在数据的末尾加上n个0,n等于除数的位数减1;

采用二进制除法规则(模2除法),计算加长的数据除以预先设定的除数,得到的余数即为循环冗余校验码;

将循环冗余校验码替换数据末尾的n个0,即得出整个传输的数据。

CRC-32是CRC的校验标准之一,其除数,即生成多项式为:

g(x)=x32+x26+x23+x22+x16+

x12+x11+x10+x8+x7+x5+x4+x2+x+1,其对应校验二进制为 100000100110000010001110110110111,16进制记为104C11DB7。

按上述规则先将要发送的二进制序列数左移32位后,再除以多项式g(x),最后得到的余数即是CRC-32码。

将CRC-32码替换发送数据末尾的32个0,得到整个传输数据。

接在收端收到整个传输数据,将数据除以多项式g(x),若余数为0,则传输正确,去掉后32位即得到需要的数据;若信道有干扰,除以多项式g(x)后余数不为0,则传输失败,等待重传。

2.模2除法计算CRC码的方法

通常的CRC算法是模仿硬件的算法,在计算一个数据段的CRC值时,其CRC值是由求解每个数值的CRC值的和对CRC寄存器的值反复更新而得到的。

假设待测数据是1101011011,生成项是10011,假设有一个4bits的寄存器,通过反复的移位和进行CRC的除法,最终该寄存器中的值就是我们所要求的余数。

3210Bits

+---+---+---+---+

Pop<--|||||<-----Augmentedmessage(已加0扩张的原始数据)

+---+---+---+---+

10011=ThePoly生成项

依据这个模型,我们得到了一个最最简单的算法:

把register中的值置0. 

  把原始的数据后添加w个0. 

  While(还有剩余没有处理的数据) 

   Begin 

  把register中的值左移一位,读入一个新的数据并置于register最低位的位置。

 

   If(如果上一步的左移操作中的移出的一位是1) 

     register=registerXORPoly. 

   End 

实际上就是模拟XOR除法的过程,即被测数据一位一位放到寄存器中来做除法。

比如生成项是10011,则生成的余数是4位XXXX,所以寄存器是4位。

待测数据是1101011011,后面加上0000,即扩张4位,以容纳余数。

只要与生成项的0011做XOR就好了,最高位经过XOR肯定出0,可不用最高位。

3.Winsock通信的原理

套接字(Socket)是网络通信的基本构件。

套接字是可以被命名的通信端点,应用程序通过它在网络上发送和接收数据。

每个套接字都有其类型,并有一个与之相连的进程。

TCP/IP提供3种类型套接字:

流式套接字(SOCK—STREAM)、数据包套接字(SOCK—DGRAM)、原始式套接字(SOCK—RAW)。

流式套接字(SOCK—STREAM)提供一个面向连接、可靠的数据传输服务,数据无差错、无重复地发送,且按发送顺序接收。

内设流量控制,避免数据流超限;数据被看作字节流,无长度限制。

流式套接字提供了一种可靠的面向连接的数据传输方式,如果想发送大批量数据或想让数据按顺序无重复地到达目的地,流式套接字最为有用。

本文使用流式套接字。

通过一个客户机/服务器模式的网络应用程序,实现对CSocket类的派生和应用为例介绍网络通信的实现。

数据集中管理需要融合各控制系统的不同数据,由于各控制系统连接在不同的网络上,要融合其中的实时信息需要解决异种网联的问题,而TCP/IP协议无疑是一个很好的选择。

对于各集中监测系统,与数据集中管理系统同在中央调度室,因此可以在遵循TCP/IP协议的局域网中进行实时通信。

在TCP/IP协议下利用Socket进行网络编程,自然就会涉及到C/S(客户机/服务器)模式,即客户端向服务器发出请求,服务器接收到请求后提供相应的服务。

客户机/服务器模式在操作过程中采取的是主动请求方式。

三、设计功能

本次实验在VC++环境下实现。

发送端:

通过键盘键入信息,对键入的信息进行CRC-32编码,将加入CRC编码的信息通过Winsock传送给接收端。

接收端:

通过Winsock监听到发送端,接收信息。

对接收到的信息进行校验,除以对应的生成项并判断余数是否为0。

余数为0则显示传输成功,否则显示传输失败。

模拟出错情况,改变传输的信息内容,测试程序校验功能。

四、程序框图

1.总程序流程图

发送端(电脑A)---------文本文件传输----------接收端(电脑B)

图4.1总程序流程图

2.基于Winsock的客户机/服务器应用程序基本结构

服务器方(接收端)

初始化本地端口,用Socket创建本地端口

绑定本地端口,用Bind()指定本地地址

倾听此端口,Listen()监听连接

客户方(发送端)

初始化本地端口用Socket创建本地端口1

接收请求,用Accept()接收请求

连接服务器端口,用Connect()连接

阻塞、等待客户请求

发送请求数据,用Send()发送

在此连接端口接受传输数据,用Receive()

在此连接端接受传输数据,用Receive()

发送响应数据,用Send()

断开连接,用Close()关闭端口

断开连接,用Close()关闭端口

结束服务

图4.2Winsock通信基本结构

五、程序清单

1.发送端电脑A源程序

#include

#include

#include

#include

#pragmacomment(lib,"Ws2_32.lib")

__int64crc;//定义全局变量crc

__int64create(__int64data,__int64POLY,intcrcbitnumber)//生成crc码子函数

{

__int64regi=0x0;//使寄存器为0

__int64data_temp;

data_temp=data;

intdatabitnumber=32;//定义数据位数,即输入的十六进制数最多8位

data<<=crcbitnumber;//data左移32位即在数据位后添加32个0

for(intcur_bit=databitnumber+crcbitnumber-1;cur_bit>=0;--cur_bit)//处理64次(32比特待测数据+32比特扩展0),前32次是加载32比特待测数据,后32次是加载一比特扩展0

{

if(((regi>>crcbitnumber)&0x0001)==0x1)regi=regi^POLY;

regi<<=1;

unsignedshorttmp=(data>>cur_bit)&0x0001;//加载待测数据1比特到tmp中,tmp只有1比特

regi|=tmp;//这1比特加载到寄存器中

}

if(((regi>>crcbitnumber)&0x0001)==0x1)

regi=regi^POLY;//做最后一次XOR

printf("\t\t\tcrc=%I64d\n",regi);

crc=regi;

data_temp<<=32;

data_temp=data_temp+regi;

returndata_temp;

}

voidSend(__int64code)

{

WORDwVersionRequested;

WSADATAwsaData;

interr;

wVersionRequested=MAKEWORD(2,2);

err=WSAStartup(wVersionRequested,&wsaData);

if(err!

=0)

{

return;

}

if(LOBYTE(wsaData.wVersion)!

=2||

HIBYTE(wsaData.wVersion)!

=2)

{

WSACleanup();

return;

}

SOCKETsocketClient=socket(AF_INET,SOCK_STREAM,0);

SOCKADDR_INaddrSrv;

addrSrv.sin_family=AF_INET;

addrSrv.sin_port=htons(6000);

addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");//服务器端的IP地址

connect(socketClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));

charrecvBuf[256];

charsendBuf[100];

recv(socketClient,recvBuf,256,0);

sprintf(sendBuf,"%I64x",code);

send(socketClient,sendBuf,strlen(sendBuf)+1,0);

closesocket(socketClient);

WSACleanup();

}

intmain()

{

__int64code;//code即为实际传输的数据

__int64data;//data为从键盘输入的数据即要传输的数据

__int64POLY=(__int64)0x254028D1*0x7;

intcrcbitnumber=32;

printf("\n\t\t**************CRC校验发送端**************\n\n");

while

(1)

{

printf("\t\t\t请输入需要传输的数据:

");

scanf("%I64x",&data);//%x,输入16进制整数

code=create(data,POLY,crcbitnumber);

printf("\t\t\tCODE=%I64x\n\n",code);

Send(code);

}

getchar();

}

2.接收端电脑B源程序

#include

#include

#include

#pragmacomment(lib,"WS2_32.lib")

__int64exam(__int64data,__int64POLY,intcrcbitnumber)

{

__int64regi=0x0;

__int64data_temp;

data_temp=data;

intdatabitnumber=32;

for(intcur_bit=databitnumber+crcbitnumber-1;cur_bit>=0;--cur_bit)

{

if(((regi>>crcbitnumber)&0x0001)==0x1)

regi=regi^POLY;

regi<<=1;

unsignedshorttmp=(data>>cur_bit)&0x0001;

regi|=tmp;

}

if(((regi>>crcbitnumber)&0x0001)==0x1)

regi=regi^POLY;

return(regi);

}

voidSolve(__int64code)

{

__int64result;

__int64POLY=(__int64)0x254028D1*0x7;

intcrcbitnumber=32;

printf("\n\t\t**************CRC校验接收端**************\n\n");

printf("\t\t\tcode=%I64x\n\n",code);

result=exam(code,POLY,crcbitnumber);

printf("\t\t\tresult=%I64x,",result);

if(result==0)

{

printf("数据传输正确!

\n\n");

code>>=32;

printf("\t\t\t去除CRC校验码后数据是%I64x。

\n\n",code);

}

elseprintf("\n\t\t\t数据传输失败。

");

}

intmain()

{

__int64code;

WORDwVersionRequested;//版本号

WSADATAwsaData;

interr;

printf("\n\t\t**************winsocket服务端**************\n\n");

wVersionRequested=MAKEWORD(2,2);//2.2版本的套接字

//加载套接字库,如果失败返回

err=WSAStartup(wVersionRequested,&wsaData);

if(err!

=0)

{

return0;

}

//判断高低字节是不是2,如果不是2.2的版本则退出

if(LOBYTE(wsaData.wVersion)!

=2||

HIBYTE(wsaData.wVersion)!

=2)

{

return0;

}

//创建流式套接字,基于TCP(SOCK_STREAM)

SOCKETsocSrv=socket(AF_INET,SOCK_STREAM,0);

//Socket地址结构体的创建

SOCKADDR_INaddrSrv;

addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//转换Unsignedlong型为网络字节序格

addrSrv.sin_family=AF_INET;//指定地址簇

addrSrv.sin_port=htons(6000);

//指定端口号,除sin_family参数外,其它参数都是网络字节序,因此需要转换

//将套接字绑定到一个端口号和本地地址上

bind(socSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//必须用sizeof,strlen不行

listen(socSrv,5);

SOCKADDR_INaddrClient;//字义用来接收客户端Socket的结构体

intlen=sizeof(SOCKADDR);//初始化参数,这个参数必须进行初始化,sizeof

//循环等待接受客户端发送请求

while

(1)

{

//等待客户请求到来;当请求到来后,接受连接请求,

//返回一个新的对应于此次连接的套接字(accept)。

//此时程序在此发生阻塞

SOCKETsockConn=accept(socSrv,(SOCKADDR*)&addrClient,&len);

charsendBuf[100];

sprintf(sendBuf,"Welcome%stoCSU",

inet_ntoa(addrClient.sin_addr));//格式化输出

//用返回的套接字和客户端进行通信

send(sockConn,sendBuf,strlen(sendBuf)+1,0);//多发送一个字节

//接收数据

charrecvBuf[100];

recv(sockConn,recvBuf,100,0);

closesocket(sockConn);

sscanf(recvBuf,"%I64x",&code);

Solve(code);

}

}

六、测试数据及结果

1.测试数据正确时

发送端:

图6.1发送端

(1)

接收端:

图6.2接收端

(1)

说明:

其中,显示的crc为411981648是十进制表示,转换为16进制,即为CODE中信息后缀内容188e5750。

余数result的结果为0,数据传输正确。

2.测试数据溢出时

发送端:

图6.3发送端

(2)

接收端:

图6.4接收端

(2)

说明:

发送9位16进制信息时,由于code最多为16位16进制,且crc32码为8位16进制数,所以溢出信息的1位最高位。

3.测试数据传输失败时

发送端:

图6.5发送端(3)

接收端:

图6.6接收端(3)

说明:

模拟传输出错情况,改变接收端接收到的数据内容,校验时余数result不为0,所以传输失败。

七、总结

1.课设过程中遇到的问题及解决方案

课设中遇到的第一个难题是数据位数的问题。

int只有4字节,而CRC-32的生成项的二进制形式为33位,在原有信息后面再加上33位后,超出了定义范围。

后经过查找资料发现,__int64可以表示8个字节,即64位,可以满足要求。

但是,VC的输入输出与__int64的兼容就不是很好,会产生错误提示“ nooperatordefinedwhichtakesaright-handoperandoftype'__int64' ”。

此时使用C的写法:

scanf("%I64d",&a)和printf("%I64d",a),就可以正确输入输出了。

课设过程中遇到的第二个大难题是生成项0x104C11DB7超出范围,和同学讨论后确定是电脑机器位数不够造成的,可以进行强制转换,经过各种尝试,最终确定强制转换类型为:

__int64POLY=(__int64)0x254028D1*0x7,其中0x254028D1*0x7=0x104C11DB7。

课设中遇到的第三个难题简直是灾难性的,那就是在第一次检查过程中才发现看错了题目条件,将Winsock通信的题目,看错是共享文件通信,所以之前在实验时都是通过共享文件实现通信信息交换。

但是人的潜力是无穷的,虽然时间紧迫,最后我还是结合在网上查找的Winsock通信代码资料,顺利将自己的代码改写完成。

并且在学习通信网的课程时进行的实验,也做过关于socket通信的相关实验,所以我对于socket的基本原理还是比较清楚的,因此这方面的代码上手比较快,加快了自己代码完成的进程。

2.课程成果反思

我所采用的CRC代码算法是模仿硬件的算法,在计算一个数据段的CRC值时,其CRC值是由求解每个数值的CRC值的和对CRC寄存器的值反复更新而得到的。

但是这种算法求CRC的速度较慢,还有一种算法可以通过查表来快速完成,叫做“驱动表法”算法。

对于“驱动表法”可以再多多思考

另外,我是通过直接修改代码中计算公式来模拟传输出错的,其实也可以在代码中多加入一个模拟出错模块,做一个选项,选择随机位数差错或者突发差错,为传输信息提供随机变化,再通过计算校验传输是否正确。

3.心得体会

这次课设让我受益匪浅,不仅让我对于CRC码算法和模2除法的原理有了透彻的理解,还让我重温了socket通信的算法。

CRC校验码的用途很多,例如CRC-32就应用在ZIP,RAR,IEEE802LAN/FDDI,IEEE1394,PPP-FCS等多个方面。

socket通信也让我对于TCP/IP协议有了更加深入的理解。

另外再次锻炼了我的C语言编程能力,也提醒我要更加注重细节,常言道细节决定成败,在编程这块这是真理。

除却在专业知识上有了更加深入的理解,我也感受到了王老师培养学生能力的拳拳之心。

感谢王老师的教育及督促,今后一定会更加努力提升自己的专业技能。

八、参考资料

[1]施荣华,王国才.《计算机通信网络技术及应用》.中国水利水电出版社2012年

[2]高传善等编著.数据通信与计算机网络,高等教育出版社,2004年

[3]INTERNET相关资料

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 自然科学 > 物理

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2