基于重叠模型的通信程序设计_第1页
基于重叠模型的通信程序设计_第2页
基于重叠模型的通信程序设计_第3页
基于重叠模型的通信程序设计_第4页
基于重叠模型的通信程序设计_第5页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、集美大学计算机工程学院实验报告课程名称:TCP/IP协议分析与编程班级:实验成绩:实验项目名称:基于重叠模型的通信程序设计学号:上机实践日期:2016-05-26实验项目编号:10组号:1上机实践时间: 2学时一、 实验目的 了解基于重叠模型通信程序的编写,编译和执行二、 实验内容与设计思想编写Win32程序实现基于重叠模型的两台计算机之间的通信,要求编程实现服务器端与客户端之间双向数据传递。客户端向服务器端发送“请输出1000以内斐波那契数列”,服务器回应客户端给出结果。(斐波那契数列特征,F0=0,F1=1,Fn=F(n-1)+F(n-2),n>=2)三、 实验使用环境操作系统: M

2、icrosoft Windows XP SP2编程环境:Visual C+ 6.0四、实验步骤和调试过程源代码服务器端:#include "stdafx.h"#include "initsock.h"#include <Mswsock.h>#include <stdio.h>#define BUFFER_SIZE 1024CInitSock initSock;/ 为每个套节字创建一个_SOCKET_OBJ对象typedef struct _SOCKET_OBJSOCKET s;/ 套节字句柄int nOutstandingOps;

3、/ 记录此套节字上的重叠I/O数量LPFN_ACCEPTEX lpfnAcceptEx;/ 扩展函数AcceptEx的指针(仅对监听套节字而言) SOCKET_OBJ, *PSOCKET_OBJ;/ 定义缓冲区对象buffer,记录重叠I/O的所有属性typedef struct _BUFFER_OBJOVERLAPPED ol;/ 重叠结构char *buff;/ send/recv/AcceptEx所使用的缓冲区int nLen;/ buff的长度PSOCKET_OBJ pSocket;/ 此I/O所属的套节字对象int nOperation;/ 提交的操作类型#define OP_ACC

4、EPT1#define OP_READ2#define OP_WRITE3SOCKET sAccept;/ 用来保存AcceptEx接受的客户套节字(仅对监听套节字而言)_BUFFER_OBJ *pNext; BUFFER_OBJ, *PBUFFER_OBJ;HANDLE g_eventsWSA_MAXIMUM_WAIT_EVENTS;/ I/O事件句柄数组int g_nBufferCount;/ 上数组中有效句柄数量PBUFFER_OBJ g_pBufferHead, g_pBufferTail;/ 记录缓冲区对象组成的表的地址/ 申请套节字对象和释放套节字对象的函数PSOCKET_OBJ

5、GetSocketObj(SOCKET s)PSOCKET_OBJ pSocket = (PSOCKET_OBJ):GlobalAlloc(GPTR, sizeof(SOCKET_OBJ);if(pSocket != NULL)pSocket->s = s;return pSocket;void FreeSocketObj(PSOCKET_OBJ pSocket)if(pSocket->s != INVALID_SOCKET):closesocket(pSocket->s);:GlobalFree(pSocket);/ 申请_BUFFER_OBJ对象的函数,每次调用重叠I/0

6、函数前需要申请PBUFFER_OBJ GetBufferObj(PSOCKET_OBJ pSocket, ULONG nLen)if(g_nBufferCount > WSA_MAXIMUM_WAIT_EVENTS - 1)return NULL;PBUFFER_OBJ pBuffer = (PBUFFER_OBJ):GlobalAlloc(GPTR, sizeof(BUFFER_OBJ);if(pBuffer != NULL)pBuffer->buff = (char*):GlobalAlloc(GPTR, nLen);pBuffer->ol.hEvent = :WSACr

7、eateEvent();pBuffer->pSocket = pSocket;pBuffer->sAccept = INVALID_SOCKET;/ 将新的BUFFER_OBJ添加到列表中if(g_pBufferHead = NULL)g_pBufferHead = g_pBufferTail = pBuffer;elseg_pBufferTail->pNext = pBuffer;g_pBufferTail = pBuffer;g_events+ g_nBufferCount = pBuffer->ol.hEvent;return pBuffer;/ 释放_BUFFE

8、R_OBJ对象的函数void FreeBufferObj(PBUFFER_OBJ pBuffer)/ 从列表中移除BUFFER_OBJ对象PBUFFER_OBJ pTest = g_pBufferHead;BOOL bFind = FALSE;if(pTest = pBuffer)g_pBufferHead = g_pBufferTail = NULL;bFind = TRUE;elsewhile(pTest != NULL && pTest->pNext != pBuffer)pTest = pTest->pNext;if(pTest != NULL)pTest-

9、>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_OBJ FindBufferObj(HANDLE hEvent)PBUFFER_OBJ pBuffer

10、= g_pBufferHead;while(pBuffer != NULL)if(pBuffer->ol.hEvent = hEvent)break;pBuffer = pBuffer->pNext;return pBuffer;/ 更新事件句柄数组g_eventsvoid RebuildArray()PBUFFER_OBJ pBuffer = g_pBufferHead;int i = 1;while(pBuffer != NULL)g_eventsi+ = pBuffer->ol.hEvent;pBuffer = pBuffer->pNext;/ 提交接收连接的_B

11、UFFER_OBJ对象BOOL PostAccept(PBUFFER_OBJ pBuffer)PSOCKET_OBJ pSocket = pBuffer->pSocket;if(pSocket->lpfnAcceptEx != NULL)/ 设置I/O类型,增加套节字上的重叠I/O计数pBuffer->nOperation = OP_ACCEPT;pSocket->nOutstandingOps +;/ 投递此重叠I/O DWORD dwBytes;pBuffer->sAccept = :WSASocket(AF_INET, SOCK_STREAM, 0, NUL

12、L, 0, WSA_FLAG_OVERLAPPED);BOOL b = 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)return

13、FALSE;return TRUE;return FALSE;/ 提交接收数据的_BUFFER_OBJ对象BOOL PostRecv(PBUFFER_OBJ pBuffer)/ 设置I/O类型,增加套节字上的重叠I/O计数pBuffer->nOperation = OP_READ;pBuffer->pSocket->nOutstandingOps +;/ 投递此重叠I/ODWORD dwBytes;DWORD dwFlags = 0;WSABUF buf;buf.buf = pBuffer->buff;buf.len = pBuffer->nLen;if(:WSA

14、Recv(pBuffer->pSocket->s, &buf, 1, &dwBytes, &dwFlags, &pBuffer->ol, NULL) != NO_ERROR)if(:WSAGetLastError() != WSA_IO_PENDING)return FALSE;return TRUE;/ 提交发送数据的_BUFFER_OBJ对象BOOL PostSend(PBUFFER_OBJ pBuffer)/ 设置I/O类型,增加套节字上的重叠I/O计数pBuffer->nOperation = OP_WRITE;pBuffer-&

15、gt;pSocket->nOutstandingOps +;/ 投递此重叠I/ODWORD dwBytes;DWORD dwFlags = 0;WSABUF buf;buf.buf = pBuffer->buff;buf.len = pBuffer->nLen;/计算1000以内斐波那契数列char str100="1000以内斐波那契数列为:"char str110;int x=0,y=1,z;for(int i=2;z<=1000;i+)z=x+y;itoa(y,str1,10);strcat(str1," ");strcat

16、(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)return FALSE;return TRUE;BO

17、OL HandleIO(PBUFFER_OBJ pBuffer)PSOCKET_OBJ pSocket = pBuffer->pSocket; / 从BUFFER_OBJ对象中提取SOCKET_OBJ对象指针,为的是方便引用pSocket->nOutstandingOps -;/ 获取重叠操作结果DWORD dwTrans;DWORD dwFlags;BOOL bRet = :WSAGetOverlappedResult(pSocket->s, &pBuffer->ol, &dwTrans, FALSE, &dwFlags);if(!bRet)/

18、 在此套节字上有错误发生,因此,关闭套节字,移除此缓冲区对象。/ 如果没有其它抛出的I/O请求了,释放此缓冲区对象,否则,等待此套节字上的其它I/O也完成if(pSocket->s != INVALID_SOCKET):closesocket(pSocket->s);pSocket->s = INVALID_SOCKET;if(pSocket->nOutstandingOps = 0)FreeSocketObj(pSocket);FreeBufferObj(pBuffer);return FALSE;/ 没有错误发生,处理已完成的I/Oswitch(pBuffer-&g

19、t;nOperation)case OP_ACCEPT:/ 接收到一个新的连接,并接收到了对方发来的第一个封包/ 为新客户创建一个SOCKET_OBJ对象PSOCKET_OBJ pClient = GetSocketObj(pBuffer->sAccept);/ 为发送数据创建一个BUFFER_OBJ对象,这个对象会在套节字出错或者关闭时释放PBUFFER_OBJ pSend = GetBufferObj(pClient, BUFFER_SIZE);if(pSend = NULL)printf(" Too much connections! n");FreeSocke

20、tObj(pClient);return FALSE;RebuildArray();/打印接收到的数据 printf("接收到的数据:%sn",pBuffer->buff) ; / 将数据复制到发送缓冲区pSend->nLen = dwTrans;memcpy(pSend->buff, pBuffer->buff, dwTrans);/ 投递此发送I/O(将数据回显给客户)if(!PostSend(pSend)/ 万一出错的话,释放上面刚申请的两个对象FreeSocketObj(pSocket);FreeBufferObj(pSend);return

21、 FALSE;/ 继续投递接受I/OPostAccept(pBuffer);break;case OP_READ:/ 接收数据完成if(dwTrans > 0)/ 创建一个缓冲区,以发送数据。这里就使用原来的缓冲区PBUFFER_OBJ pSend = pBuffer;pSend->nLen = dwTrans;/ 投递发送I/O(将数据回显给客户)PostSend(pSend);else/ 套节字关闭/ 必须先关闭套节字,以便在此套节字上投递的其它I/O也返回if(pSocket->s != INVALID_SOCKET):closesocket(pSocket->s

22、);pSocket->s = INVALID_SOCKET;if(pSocket->nOutstandingOps = 0)FreeSocketObj(pSocket);FreeBufferObj(pBuffer);return FALSE;break;case OP_WRITE:/ 发送数据完成if(dwTrans > 0)/ 继续使用这个缓冲区投递接收数据的请求pBuffer->nLen = BUFFER_SIZE;PostRecv(pBuffer);else/ 套节字关闭/ 同样,要先关闭套节字if(pSocket->s != INVALID_SOCKET)

23、:closesocket(pSocket->s);pSocket->s = INVALID_SOCKET;if(pSocket->nOutstandingOps = 0)FreeSocketObj(pSocket);FreeBufferObj(pBuffer);return FALSE;break;return TRUE;void main()/ 创建监听套节字,绑定到本地端口,进入监听模式int nPort = 4567;SOCKET sListen = :WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_F

24、LAG_OVERLAPPED);SOCKADDR_IN si;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_OBJ pListen = GetSocketObj(sListen);/ 加载扩展函数AcceptExGUID GuidAcceptEx = WSAID_AC

25、CEPTEX;DWORD dwBytes;WSAIoctl(pListen->s, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx, sizeof(GuidAcceptEx),&pListen->lpfnAcceptEx, sizeof(pListen->lpfnAcceptEx), &dwBytes, NULL, NULL);/ 创建用来重新建立g_events数组的事件对象g_events0 = :WSACreateEvent();/ 在此可以投递多个接受I/O请求for(int i=0; i&l

26、t;5; i+)PostAccept(GetBufferObj(pListen, BUFFER_SIZE);:WSASetEvent(g_events0);while(TRUE)int nIndex = :WSAWaitForMultipleEvents(g_nBufferCount + 1, g_events, FALSE, WSA_INFINITE, FALSE);if(nIndex = WSA_WAIT_FAILED)printf("WSAWaitForMultipleEvents() failed n");break;nIndex = nIndex - WSA_WA

27、IT_EVENT_0;for(int i=0; i<=nIndex; i+)int nRet = :WSAWaitForMultipleEvents(1, &g_eventsi, TRUE, 0, FALSE);if(nRet = WSA_WAIT_TIMEOUT)continue;else:WSAResetEvent(g_eventsi);/ 重新建立g_events数组if(i = 0)RebuildArray();continue;/ 处理这个I/OPBUFFER_OBJ pBuffer = FindBufferObj(g_eventsi);if(pBuffer != NU

28、LL)if(!HandleIO(pBuffer)RebuildArray();客户端:#include <stdio.h>#include <winsock2.h>#pragma comment(lib, "WS2_32")/ 链接到WS2_32.libclass CInitSockpublic:CInitSock(BYTE minorVer = 2, BYTE majorVer = 2)/ 初始化WS2_32.dllWSADATA wsaData;WORD sockVersion = MAKEWORD(minorVer, majorVer);if(:WSAStartup(sockVersion, &wsaData) != 0) return;CInitSock():WSACleanup();CInitSock theSock; /加载套接字库int main()/ 创建套节字SOCKET s = :socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if(s = INVALI

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论