UDP服务器课程设计.docx
- 文档编号:30185243
- 上传时间:2023-08-05
- 格式:DOCX
- 页数:18
- 大小:195.31KB
UDP服务器课程设计.docx
《UDP服务器课程设计.docx》由会员分享,可在线阅读,更多相关《UDP服务器课程设计.docx(18页珍藏版)》请在冰豆网上搜索。
UDP服务器课程设计
目录
课程设计的目的和意义2
课程设计的内容和要求3
课程设计过程8
发送部分代码实现:
9
接收部分代码实现:
12
数据处理部分:
15
处理部分如下:
18
心得体会20
参考文献21
课程设计的目的和意义
随着经济的发展,社会的进步,计算机越来越深入到我们日常的工作学习及生活中,成为我们日常生活中不可缺少的辅助工具。
随着科学技术的不断提高,计算机科学日渐成熟,其强大的功能已为人们深刻认识,它已进入人类社会的各个领域并发挥着越来越重要的作用。
它已经深入到日常工作和生活的方方面面,比如文字处理、信息管理、辅助设计、图形图像处理、教育培训以及游戏娱乐等。
各行各业的人们无须经过特别的训练就能够使用电脑完成许许多多复杂的工作。
然而,虽然现在世界上已经充满了多如牛毛的各种软件,但它们依然不能满足用户的各种特殊需要,人们还不得不开发适合自己特殊需求的软件。
以前开发Windows应用软件是专业人员的工作,需要掌握许多专业知识和经过特殊的培训才能胜任。
现在不同了,即使你没有接受过严格的程序设计训练,使用各种可视化编程软件也一样能够开发出功能强大、适合自己特殊需求的应用程序了。
特特别是现在越来越发达的网络,随之而来的是巨大的网络数据传输,这就涉及到一系列的网络编程技术。
通常程序所使用的每个UDP端口都与一个有限大小的输入队列相联系。
这意味着,来自不同客户的差不多同时到达的请求将由UDP自动排队。
接收到的UDP数据报以其接收顺序交给应用程序(在应用程序要求交送下一个数据报时)。
UDP在一个较低水平上完成了通信,在收到分组的时候没有流量控制机制,也没有确认机制,适用于可靠性能比较好的局域网,由于UDP采取了无连接方式,因此协议简单,在一些特定的应用中协议运行效率高。
UDP使用与一些实时的应用,如IP电话等,它们要求源主机以恒定的速率发送时数据,并且在网络出现拥塞时可以丢失一些数据,但是迟延不能太大。
基于这些特点,流式多媒体通信,多播等应用在传输层采用的就是UDP协议。
因为本人能力有限,加上时间紧迫,所以设计出来的本系统可能功能比较简单,另外本系统是单机版,不能实现网络互联操作,这些都有待于我在以后的工作学习中进一步改进。
课程设计的内容和要求
UDP(UserDataProtocol,用户数据报协议)是与TCP相对应的协议。
它是面向非连接的协议,它不与对方建立连接,而是直接就把数据包发送过去!
UDP适用于一次只传送少量数据、对可靠性要求不高的应用环境。
比如,我们经常使用“ping”命令来测试两台主机之间TCP/IP通信是否正常,其实“ping”命令的原理就是向对方主机发送UDP数据包,然后对方主机确认收到数据包,如果数据包是否到达的消息及时反馈回来,那么网络就是通的。
例如,在默认状态下,一次“ping”操作发送4个数据包。
可以看到,发送的数据包数量是4包,收到的也是4包(因为对方主机收到后会发回一个确认收到的数据包)。
这充分说明了UDP协议是面向非连接的协议,没有建立连接的过程。
正因为UDP协议没有连接的过程,所以它的通信效果高;但也正因为如此,它的可靠性不如TCP协议高。
本次课程设计的内容就是设计一个UDP服务器实现文件视屏的传输,能对多个个客户端进行管理的实现。
而实现的功能是基于VC++6.0上实现,使用的接口函数是WinsockAPI,使用的函数简单介绍如下:
intWSAStartupo(WORDwVersionRequested,LPWSADATAlpWSAData);
wVersionRequested参数用于指定准备加载的Winsock库的版本。
高位字节指定所需要的Winsock库的副版本,而低位字节册是主版本。
可用MAKEWORD(X,Y)(其中,x是高位字节,y是低位字节)方便地获得wVersionRequested的正确值。
ipWSAData参数是指想WSADATA结构的指针,WSAStartup用其加载的库版本有关的信息填在这个结构中。
SOCKETsocket(
intaf,
inttype,
intprotocol
);
接收三个参数。
第一个参数af指定地址族,对于TCP/IP协议的套接字,它只能是AF_INET(也可写成PF_INET)。
第二个参数指定Socket类型,对于1.1版本的Socket,它只支持两种类型的套接字,SOCK_STREAM指定产生流式套接字,SOCK_DGRAM产生数据报套接字。
第三个参数是与指定的地址家族相关的协议,如果指定为0,那么它就会根据地址格式和套接字类别,自动为你选择一个合适的协议。
这是推荐使用的一种选择协议的方法。
如果这个函数调用成功,他将返回一个新的SOCKET数据类型的套接字描述符。
如果调用失败,这个函数就会返回一个INVAID_SOCKET,错误信息可以通过WSAGetLastError函数返回。
intbind(
SOCKETs,
conststructsockaddrFAR* name,
intnamelen
);
接收三个参数。
第一个参数s指定要绑定的套接字,第二个参数指定了该套接字的班底地址信息,是指向sockaddr结构的指针变量,由于该地址结构是为所有的地址家族准备的,这个结构可能(通常会)随所使用的网络协议不同而不同,所以,要用第三个参数指定该地址结构的长度。
sockaddr结构定义如下:
structsockaddr{
u_shortsa_family;
charsa_data[14];
};
sockaddr的第一个字段sa_family指定该地址家族,在这里必须设为AF_INET。
sa_data仅仅是表示要求一块内存分配区,起到占位的作用,该区域中指定的协议相关的具体地址信息。
由于实际要求的只是内存区,所以对于不同的协议家族,用不同的结构来替换sockaddr。
除了sa_family外,sockaddr是按网络字节顺序表示的。
在TCP/IP中,我们可以用sockaddr_in结构替换sockaddr,以方便我们填写地址信息。
u_longhtonl(
u_longhostlong );
转换一个u_long类型从主机字节序到TCP/IP网络字节序。
u_shorthtons(
u_shorthostshort
);
转换一个u_short类型从主机字节序到TCP/IP网络字节序。
intlisten(
SOCKETs,
intbacklog
);
将套接字设置为监听模式,监听连接请求。
第一个参数为套接字描述符,第二个参数为等待连接队列的最大长度。
SOCKETaccept(
SOCKETs,
structsockaddrFAR*addr,
intFAR*addrlen
);
等待客户连接到来,并接受连接请求。
第一个为处于监听状态的套接字。
第二个是一个out,指向一个buffer指针用来接收连接实体的地址。
当发起连接时,保存了发起连接的客户端的IP地址信息和端口信息。
第三个参数用来包含所返回的地址结构的长度。
intsend(
SOCKETs,
constcharFAR*buf,
intlen,
intflags
);
第一个是套接字,第二个是buffer,包含了将要被传送的数据,第三个是buffer中数据的长度,第四个flags将影响send调用行为。
intrecv(
SOCKETs,
charFAR*buf,
intlen,
intflags
);
第一个是套接字,第二个是buffer,包含了将要被接收的数据,第三个是buffer中数据的长度,第四个flags将影响send调用行为。
intconnect(
SOCKETs,
conststructsockaddrFAR* name,
intnamelen
);
课程设计过程
设计UDP服务器的过程如下所示,首先,创建一个Socket并监听事件,然后启动线程接收数据,用一个链表保存所有连上的客户,并通知连接成功,这样,客户就有机会处理这一事件并作一些动作,最后,当客户断开时,向服务器发送一个事件,服务器就可以做一些收尾的工作。
服务器工作流程如下:
客户机一端工作的流程如下:
1.打开通信信道(申请一个套接字),并连接到服务器在主机的保留端口,该端口对应的服务器的UDP进程。
2.向服务器发出请求报文,等待接收应答。
3.从服务器方收到的最终应答结果,或在不再请求时关闭信道并终止客户进程。
服务器一端的工作流程如下:
1.打开通信通道(申请一个套接字),通知本地主机在某一保留端口接收客户机请求到达指定端口。
2.等待客户请求到达指定端口。
3.接收到请求,启动一个新进程处理用户请求,同时释放旧进程以响应新的客户请求,一旦服务完成,关闭新进程与客户的通信链路。
4.继续等待客户机请求。
5.如果不想响应客户机的请求,关闭服务器进程。
发送部分代码实现:
BOOLCUdpSock:
:
SendBuffer(char*buff,DWORDdwBufSize,structsockaddrFAR*lpTo)
{
m_lock.Lock();
WSABUFwsabuf;
WSAOVERLAPPEDover;
DWORDdwRecv;
DWORDdwFlags=0;
DWORDdwRet;
BOOLfPending;
intnRet;
//
//SetuptheWSABUFandWSAOVERLAPPEDstructures
//
memset(&over,0,sizeof(WSAOVERLAPPED));
wsabuf.buf=buff;
wsabuf.len=dwBufSize;
over.hEvent=WSACreateEvent();
fPending=FALSE;
nRet=WSASendTo(m_Socket,//Socket
&wsabuf,//WSABUF
1,//Numberofbuffers
&dwRecv,//Bytesreceived
dwFlags,//Flags
lpTo,
sizeof(sockaddr),
&over,//WSAOVERLAPPED
NULL);//Completionfunction
if(nRet!
=0)
{
interro=WSAGetLastError();
if(erro==WSA_IO_PENDING)
fPending=TRUE;
else
{
TRACE1("CUdpSock:
:
SendBuffererro%d\n",erro);
CloseHandle(over.hEvent);
returnFALSE;
}
}
//
//IftheI/Oisn'tfinished...
//
if(fPending)
{
//
//Waitfortherequesttocomplete
//ortheexiteventtobesignaled
//
dwRet=WaitForSingleObject(over.hEvent,60000);
//
//Wastherecveventsignaled?
//
if(dwRet==WAIT_TIMEOUT)//WAIT_OBJECT_0/WAIT_TIMEOUT
{
CloseHandle(over.hEvent);
TRACE("WAIT_TIMEOUT发送失败\n",NULL);
returnFALSE;
}
if(dwRet!
=WAIT_OBJECT_0)//WAIT_OBJECT_0/WAIT_TIMEOUT
{
CloseHandle(over.hEvent);
TRACE("发送失败\n",NULL);
returnFALSE;
}
//
//GetI/Oresult
//
if(!
WSAGetOverlappedResult(m_Socket,
&over,
&dwRecv,
FALSE,
&dwFlags))
{
CloseHandle(over.hEvent);
TRACE("WSAGetOverlappedResult发送失败\n",NULL);
returnFALSE;
}
}
CloseHandle(over.hEvent);
TRACE("发送成功\n",NULL);
m_lock.Unlock();
returnTRUE;
}
接收部分代码实现:
BOOLCUdpSock:
:
RecvRequest(LPBYTEpBuf,DWORDdwBufSize,structsockaddrFAR*lpFrom)
{
WSAOVERLAPPEDover;
WSABUFwsabuf;
DWORDdwRecv;
DWORDdwFlags;
DWORDdwRet;
HANDLEhEvents[2];
BOOLfPending;
intnRet;
//
//Zerothebuffersotherecvisnull-terminated
//
memset(pBuf,0,dwBufSize);
//
//SetuptheWSABUFandWSAOVERLAPPEDstructures
//
wsabuf.buf=(char*)pBuf;
wsabuf.len=dwBufSize;
memset(&over,0,sizeof(WSAOVERLAPPED));
over.hEvent=m_hEventSock;
dwFlags=0;
fPending=FALSE;
intsizeAddr=sizeof(sockaddr_in);
nRet=WSARecvFrom(m_Socket,//Socket
&wsabuf,//WSABUF
1,//Numberofbuffers
&dwRecv,//Bytesreceived
&dwFlags,//Flags
lpFrom,
&sizeAddr,
&over,//WSAOVERLAPPED
NULL);//Completionfunction
if(nRet!
=0)
{
if(WSAGetLastError()!
=WSA_IO_PENDING)
{
returnFALSE;
}
else
fPending=TRUE;
}
//
//IftheI/Oisn'tfinished...
//
if(fPending)
{
//
//Waitfortherequesttocompleteortheexitevent
//
hEvents[0]=over.hEvent;
hEvents[1]=m_hEventExit;
dwRet=WaitForMultipleObjects(2,
hEvents,
FALSE,
INFINITE);
//
//Wastherecveventsignaled?
//
if(dwRet!
=0)
{
returnFALSE;
}
if(!
WSAGetOverlappedResult(m_Socket,
&over,
&dwRecv,
FALSE,
&dwFlags))
returnFALSE;
}
//
//Recveventiscomplete--keepstatistics
//
m_translate=dwRecv;
returnTRUE;
}
数据处理部分:
BOOLCUdpSock:
:
DelWithResData(structsockaddrFAR*lpFrom)
{
DWORDlenPag=sizeof(PackHead);
DWORDstart=0;
DWORDonePagLeft=0;
SockPagspags;
if(m_bFillHead)
{
onePagLeft=m_PackHead.len-lenPag;
if(m_SimpleIOBuffer.GetBufferLen() { TRACE("Thereisnoenoughpackegelength! 1\n"); returnFALSE; } ASSERT(onePagLeft<=IOBUFFLEN); pags.buff=newchar[onePagLeft]; if(m_SimpleIOBuffer.Read(pags.buff,onePagLeft)) { pags.len=onePagLeft; pags.cm=m_PackHead.cm; if(m_pResInterFace) { m_pResInterFace->Excute(&pags,lpFrom); m_bFillHead=FALSE; DelWithResData(lpFrom); } } delete[]pags.buff; }else { while(m_SimpleIOBuffer.Read((char*)&m_PackHead,lenPag)) { if(m_PackHead.ID[0]! ='T'&&m_PackHead.ID[1]! ='P') { m_SimpleIOBuffer.Reset(); m_bFillHead=FALSE; TRACE("Thereispackege2iserro! \n"); returnFALSE; } m_bFillHead=TRUE; onePagLeft=m_PackHead.len-lenPag; if(m_SimpleIOBuffer.GetBufferLen() { TRACE("Thereisnoenoughpackegelength! 2\n"); returnFALSE; } ASSERT(onePagLeft<=IOBUFFLEN); pags.buff=newchar[onePagLeft]; if(m_SimpleIOBuffer.Read(pags.buff,onePagLeft)) { pags.len=onePagLeft; pags.cm=m_PackHead.cm; if(m_pResInterFace) { m_pResInterFace->Excute(&pags,lpFrom); m_bFillHead=FALSE; } } delete[]pags.buff; } } returnTRUE; } 处理部分如下: voidCUdpSock: : OnRead() { m_translate=0; sockaddr_inaddrfro; memset(&addrfro,0,sizeof(sockaddr_in)); addrfro.sin_family=AF_INET; if(! RecvRequest((LPBYTE)m_wsaInBuffer.buf,sizeof(m_byInBuffer),(sockaddr*)&addrfro)) { TRACE("CClientOverlappedSock: : OnRead\n"); return; } if(m_translate) { m_SimpleIOBuffer.Write(m_wsaInBuffer.buf,m_translate); try{ DelWithResData((sockaddr*)&addrfro); }catch(...){ TRACE("UdpDelWithResDataerro! \n"); memset(&m_PackHead,0,sizeof(PackHead)); m_bFillHead=FALSE; } m_SimpleIOBuffer.Notify(); } return; } 心得体会 一周的课程设计转瞬而逝,在这段有限的时间里,我真正领悟到了编程的乐趣并积极参与到里面,从更深的层面了解到了网络编程的意义。 本次课程设计围绕UDP服务器的设计而开展,是以C/S模式进行的工作,涉及到Winsock编程,还要用到WinsockAPI函数,开始的时候,我并没有多少头绪,因为在以前的学习中只注重了理论基础方面的积累,而实践方面并未有多少加强,不过我有信心做好这一项课设。 在第一天通过上网查找资料翻阅书籍了解到了UDP一些基本的知识,了解到了UDP服务器的工作原理,并从网站上下载了一些代码并在电脑上调试成功,然后自己根据书本要求进行代码实现,这是一件比较痛苦的事情,每次遇到错误的时候,我都会从网上找一堆资料进行分析排错,甚至有时候一个上午就解决一个错误,我深深体会到了作为一个程序员的不易。 在接下来的几天里,我继续围绕数据处理进行代码的堆砌,由于有书本作为参照,这一个过程实现很顺利,不过在进行代码整合的问题上遇到了一个不小的麻烦,在书上涉及到的例子中缺少了一个头文件,编译的时候出现了错误,于是我通过网络这一资源库,找到了问题所在,并最后解决了该问题。 通过这次课程设计,我了解到在现代社会高速发展的同时,及时跟上信息技术的脚步显得异常重要,因为现在的电子信息技术与人们的生活息息相关,并且学习网络重要的问题之一是掌握广域网和局域
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- UDP 服务器 课程设计