基于重叠模型的通信程序设计.docx
- 文档编号:23318986
- 上传时间:2023-05-16
- 格式:DOCX
- 页数:20
- 大小:38.62KB
基于重叠模型的通信程序设计.docx
《基于重叠模型的通信程序设计.docx》由会员分享,可在线阅读,更多相关《基于重叠模型的通信程序设计.docx(20页珍藏版)》请在冰豆网上搜索。
基于重叠模型的通信程序设计
集美大学计算机工程学院实验报告
课程名称:
TCP/IP协议分析与编程
班级:
实验成绩:
实验项目名称:
基于重叠模型的通信程序设计
学号:
上机实践日期:
2016-05-26
实验项目编号:
10
组号:
1
上机实践时间:
2学时
一、实验目的
了解基于重叠模型通信程序的编写,编译和执行
二、实验内容与设计思想
编写Win32程序实现基于重叠模型的两台计算机之间的通信,要求编程实现服务器端与客户端之间双向数据传递。
客户端向服务器端发送“请输出1000以内斐波那契数列”,服务器回应客户端给出结果。
(斐波那契数列特征,F0=0,F1=1,Fn=F(n-1)+F(n-2),n>=2)
三、实验使用环境
操作系统:
MicrosoftWindowsXPSP2
编程环境:
VisualC++6.0
四、实验步骤和调试过程
源代码
服务器端:
#include"stdafx.h"
#include"initsock.h"
#include
#include
#defineBUFFER_SIZE1024
CInitSockinitSock;
//为每个套节字创建一个_SOCKET_OBJ对象
typedefstruct_SOCKET_OBJ
{
SOCKETs;//套节字句柄
intnOutstandingOps;//记录此套节字上的重叠I/O数量
LPFN_ACCEPTEXlpfnAcceptEx;//扩展函数AcceptEx的指针(仅对监听套节字而言)
}SOCKET_OBJ,*PSOCKET_OBJ;
//定义缓冲区对象buffer,记录重叠I/O的所有属性
typedefstruct_BUFFER_OBJ
{
OVERLAPPEDol;//重叠结构
char*buff;//send/recv/AcceptEx所使用的缓冲区
intnLen;//buff的长度
PSOCKET_OBJpSocket;//此I/O所属的套节字对象
intnOperation;//提交的操作类型
#defineOP_ACCEPT1
#defineOP_READ2
#defineOP_WRITE3
SOCKETsAccept;//用来保存AcceptEx接受的客户套节字(仅对监听套节字而言)
_BUFFER_OBJ*pNext;
}BUFFER_OBJ,*PBUFFER_OBJ;
HANDLEg_events[WSA_MAXIMUM_WAIT_EVENTS];//I/O事件句柄数组
intg_nBufferCount;//上数组中有效句柄数量
PBUFFER_OBJg_pBufferHead,g_pBufferTail;//记录缓冲区对象组成的表的地址
//申请套节字对象和释放套节字对象的函数
PSOCKET_OBJGetSocketObj(SOCKETs)
{
PSOCKET_OBJpSocket=(PSOCKET_OBJ):
:
GlobalAlloc(GPTR,sizeof(SOCKET_OBJ));
if(pSocket!
=NULL)
{
pSocket->s=s;
}
returnpSocket;
}
voidFreeSocketObj(PSOCKET_OBJpSocket)
{
if(pSocket->s!
=INVALID_SOCKET)
:
:
closesocket(pSocket->s);
:
:
GlobalFree(pSocket);
}
//申请_BUFFER_OBJ对象的函数,每次调用重叠I/0函数前需要申请
PBUFFER_OBJGetBufferObj(PSOCKET_OBJpSocket,ULONGnLen)
{
if(g_nBufferCount>WSA_MAXIMUM_WAIT_EVENTS-1)
returnNULL;
PBUFFER_OBJpBuffer=(PBUFFER_OBJ):
:
GlobalAlloc(GPTR,sizeof(BUFFER_OBJ));
if(pBuffer!
=NULL)
{
pBuffer->buff=(char*):
:
GlobalAlloc(GPTR,nLen);
pBuffer->ol.hEvent=:
:
WSACreateEvent();
pBuffer->pSocket=pSocket;
pBuffer->sAccept=INVALID_SOCKET;
//将新的BUFFER_OBJ添加到列表中
if(g_pBufferHead==NULL)
{
g_pBufferHead=g_pBufferTail=pBuffer;
}
else
{
g_pBufferTail->pNext=pBuffer;
g_pBufferTail=pBuffer;
}
g_events[++g_nBufferCount]=pBuffer->ol.hEvent;
}
returnpBuffer;
}
//释放_BUFFER_OBJ对象的函数
voidFreeBufferObj(PBUFFER_OBJpBuffer)
{
//从列表中移除BUFFER_OBJ对象
PBUFFER_OBJpTest=g_pBufferHead;
BOOLbFind=FALSE;
if(pTest==pBuffer)
{
g_pBufferHead=g_pBufferTail=NULL;
bFind=TRUE;
}
else
{
while(pTest!
=NULL&&pTest->pNext!
=pBuffer)
pTest=pTest->pNext;
if(pTest!
=NULL)
{
pTest->pNext=pBuffer->pNext;
if(pTest->pNext==NULL)
g_pBufferTail=pTest;
bFind=TRUE;
}
}
//释放它占用的内存空间
if(bFind)
{
g_nBufferCount--;
:
:
CloseHandle(pBuffer->ol.hEvent);
:
:
GlobalFree(pBuffer->buff);
:
:
GlobalFree(pBuffer);
}
}
//在缓冲区列表中查找_BUFFER_OBJ对象
PBUFFER_OBJFindBufferObj(HANDLEhEvent)
{
PBUFFER_OBJpBuffer=g_pBufferHead;
while(pBuffer!
=NULL)
{
if(pBuffer->ol.hEvent==hEvent)
break;
pBuffer=pBuffer->pNext;
}
returnpBuffer;
}
//更新事件句柄数组g_events
voidRebuildArray()
{
PBUFFER_OBJpBuffer=g_pBufferHead;
inti=1;
while(pBuffer!
=NULL)
{
g_events[i++]=pBuffer->ol.hEvent;
pBuffer=pBuffer->pNext;
}
}
//提交接收连接的_BUFFER_OBJ对象
BOOLPostAccept(PBUFFER_OBJpBuffer)
{
PSOCKET_OBJpSocket=pBuffer->pSocket;
if(pSocket->lpfnAcceptEx!
=NULL)
{
//设置I/O类型,增加套节字上的重叠I/O计数
pBuffer->nOperation=OP_ACCEPT;
pSocket->nOutstandingOps++;
//投递此重叠I/O
DWORDdwBytes;
pBuffer->sAccept=
:
:
WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
BOOLb=pSocket->lpfnAcceptEx(pSocket->s,
pBuffer->sAccept,
pBuffer->buff,
BUFFER_SIZE-((sizeof(sockaddr_in)+16)*2),
sizeof(sockaddr_in)+16,
sizeof(sockaddr_in)+16,
&dwBytes,
&pBuffer->ol);
if(!
b)
{
if(:
:
WSAGetLastError()!
=WSA_IO_PENDING)
returnFALSE;
}
returnTRUE;
}
returnFALSE;
};
//提交接收数据的_BUFFER_OBJ对象
BOOLPostRecv(PBUFFER_OBJpBuffer)
{
//设置I/O类型,增加套节字上的重叠I/O计数
pBuffer->nOperation=OP_READ;
pBuffer->pSocket->nOutstandingOps++;
//投递此重叠I/O
DWORDdwBytes;
DWORDdwFlags=0;
WSABUFbuf;
buf.buf=pBuffer->buff;
buf.len=pBuffer->nLen;
if(:
:
WSARecv(pBuffer->pSocket->s,&buf,1,&dwBytes,&dwFlags,&pBuffer->ol,NULL)!
=NO_ERROR)
{
if(:
:
WSAGetLastError()!
=WSA_IO_PENDING)
returnFALSE;
}
returnTRUE;
}
//提交发送数据的_BUFFER_OBJ对象
BOOLPostSend(PBUFFER_OBJpBuffer)
{
//设置I/O类型,增加套节字上的重叠I/O计数
pBuffer->nOperation=OP_WRITE;
pBuffer->pSocket->nOutstandingOps++;
//投递此重叠I/O
DWORDdwBytes;
DWORDdwFlags=0;
WSABUFbuf;
buf.buf=pBuffer->buff;
buf.len=pBuffer->nLen;
//计算1000以内斐波那契数列
charstr[100]="1000以内斐波那契数列为:
";
charstr1[10];
intx=0,y=1,z;
for(inti=2;z<=1000;i++)
{
z=x+y;
itoa(y,str1,10);
strcat(str1,"");
strcat(str,str1);
x=y;
y=z;
}
buf.buf=str;
buf.len=strlen(str);
//发送数据给客户端
printf("发送数据:
\n");
printf("%s",str);
if(:
:
WSASend(pBuffer->pSocket->s,
&buf,1,&dwBytes,dwFlags,&pBuffer->ol,NULL)!
=NO_ERROR)
{
if(:
:
WSAGetLastError()!
=WSA_IO_PENDING)
returnFALSE;
}
returnTRUE;
}
BOOLHandleIO(PBUFFER_OBJpBuffer)
{
PSOCKET_OBJpSocket=pBuffer->pSocket;//从BUFFER_OBJ对象中提取SOCKET_OBJ对象指针,为的是方便引用
pSocket->nOutstandingOps--;
//获取重叠操作结果
DWORDdwTrans;
DWORDdwFlags;
BOOLbRet=:
:
WSAGetOverlappedResult(pSocket->s,&pBuffer->ol,&dwTrans,FALSE,&dwFlags);
if(!
bRet)
{
//在此套节字上有错误发生,因此,关闭套节字,移除此缓冲区对象。
//如果没有其它抛出的I/O请求了,释放此缓冲区对象,否则,等待此套节字上的其它I/O也完成
if(pSocket->s!
=INVALID_SOCKET)
{
:
:
closesocket(pSocket->s);
pSocket->s=INVALID_SOCKET;
}
if(pSocket->nOutstandingOps==0)
FreeSocketObj(pSocket);
FreeBufferObj(pBuffer);
returnFALSE;
}
//没有错误发生,处理已完成的I/O
switch(pBuffer->nOperation)
{
caseOP_ACCEPT:
//接收到一个新的连接,并接收到了对方发来的第一个封包
{
//为新客户创建一个SOCKET_OBJ对象
PSOCKET_OBJpClient=GetSocketObj(pBuffer->sAccept);
//为发送数据创建一个BUFFER_OBJ对象,这个对象会在套节字出错或者关闭时释放
PBUFFER_OBJpSend=GetBufferObj(pClient,BUFFER_SIZE);
if(pSend==NULL)
{
printf("Toomuchconnections!
\n");
FreeSocketObj(pClient);
returnFALSE;
}
RebuildArray();
//打印接收到的数据
printf("接收到的数据:
%s\n",pBuffer->buff);
//将数据复制到发送缓冲区
pSend->nLen=dwTrans;
memcpy(pSend->buff,pBuffer->buff,dwTrans);
//投递此发送I/O(将数据回显给客户)
if(!
PostSend(pSend))
{
//万一出错的话,释放上面刚申请的两个对象
FreeSocketObj(pSocket);
FreeBufferObj(pSend);
returnFALSE;
}
//继续投递接受I/O
PostAccept(pBuffer);
}
break;
caseOP_READ:
//接收数据完成
{
if(dwTrans>0)
{
//创建一个缓冲区,以发送数据。
这里就使用原来的缓冲区
PBUFFER_OBJpSend=pBuffer;
pSend->nLen=dwTrans;
//投递发送I/O(将数据回显给客户)
PostSend(pSend);
}
else//套节字关闭
{
//必须先关闭套节字,以便在此套节字上投递的其它I/O也返回
if(pSocket->s!
=INVALID_SOCKET)
{
:
:
closesocket(pSocket->s);
pSocket->s=INVALID_SOCKET;
}
if(pSocket->nOutstandingOps==0)
FreeSocketObj(pSocket);
FreeBufferObj(pBuffer);
returnFALSE;
}
}
break;
caseOP_WRITE:
//发送数据完成
{
if(dwTrans>0)
{
//继续使用这个缓冲区投递接收数据的请求
pBuffer->nLen=BUFFER_SIZE;
PostRecv(pBuffer);
}
else//套节字关闭
{
//同样,要先关闭套节字
if(pSocket->s!
=INVALID_SOCKET)
{
:
:
closesocket(pSocket->s);
pSocket->s=INVALID_SOCKET;
}
if(pSocket->nOutstandingOps==0)
FreeSocketObj(pSocket);
FreeBufferObj(pBuffer);
returnFALSE;
}
}
break;
}
returnTRUE;
}
voidmain()
{
//创建监听套节字,绑定到本地端口,进入监听模式
intnPort=4567;
SOCKETsListen=
:
:
WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);
SOCKADDR_INsi;
si.sin_family=AF_INET;
si.sin_port=:
:
ntohs(nPort);
si.sin_addr.S_un.S_addr=INADDR_ANY;
:
:
bind(sListen,(sockaddr*)&si,sizeof(si));
:
:
listen(sListen,200);
//为监听套节字创建一个SOCKET_OBJ对象
PSOCKET_OBJpListen=GetSocketObj(sListen);
//加载扩展函数AcceptEx
GUIDGuidAcceptEx=WSAID_ACCEPTEX;
DWORDdwBytes;
WSAIoctl(pListen->s,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&GuidAcceptEx,
sizeof(GuidAcceptEx),
&pListen->lpfnAcceptEx,
sizeof(pListen->lpfnAcceptEx),
&dwBytes,
NULL,
NULL);
//创建用来重新建立g_events数组的事件对象
g_events[0]=:
:
WSACreateEvent();
//在此可以投递多个接受I/O请求
for(inti=0;i<5;i++)
{
PostAccept(GetBufferObj(pListen,BUFFER_SIZE));
}
:
:
WSASetEvent(g_events[0]);
while(TRUE)
{
intnIndex=
:
:
WSAWaitForMultipleEvents(g_nBufferCount+1,g_events,FALSE,WSA_INFINITE,FALSE);
if(nIndex==WSA_WAIT_FAILED)
{
printf("WSAWaitForMultipleEvents()failed\n");
break;
}
nIndex=nIndex-WSA_WAIT_EVENT_0;
for(inti=0;i<=nIndex;i++)
{
intnRet=:
:
WSAWaitForMultipleEvents(1,&g_events[i],TRUE,0,FALSE);
if(nRet==WSA_WAIT_TIMEOUT)
continue;
else
{
:
:
WSAResetEvent(g_events[i]);
//重新建立g_events数组
if(i==0)
{
RebuildArray();
continue;
}
//处理这个I/O
PBUFFER_OBJpBuffer=FindBufferObj(g_events[i]);
if(pBuffer!
=NULL)
{
if(!
HandleIO(pBuffer))
RebuildArray();
}
}
}
}
}
客户端:
#include
#include
#pragmacomment(lib,"WS2_32")//链接到WS2_32.lib
classCInitSock
{
public:
CInitSock(BYTEminorVer=2,BYTEmajorVer=2)
{
//初始化WS2_32.dll
WSADATAwsaData;
WORDsockVersion=MAKEWORD(minorVer,majorVer);
if(:
:
WSAStartup(sockVersion,&wsaData)!
=0)
return;
}
~CInitSock()
{
:
:
WSACleanup();
}
};
CInitSocktheSock
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基于 重叠 模型 通信 程序设计