收藏 分享(赏)

基于重叠模型的通信程序设计.doc

上传人:gnk289057 文档编号:6206894 上传时间:2019-04-02 格式:DOC 页数:15 大小:97KB
下载 相关 举报
基于重叠模型的通信程序设计.doc_第1页
第1页 / 共15页
基于重叠模型的通信程序设计.doc_第2页
第2页 / 共15页
基于重叠模型的通信程序设计.doc_第3页
第3页 / 共15页
基于重叠模型的通信程序设计.doc_第4页
第4页 / 共15页
基于重叠模型的通信程序设计.doc_第5页
第5页 / 共15页
点击查看更多>>
资源描述

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

2、操作系统: Microsoft Windows XP SP2编程环境:Visual C+ 6.0四、实验步骤和调试过程源代码服务器端:#include “stdafx.h“#include “initsock.h“#include #include #define BUFFER_SIZE 1024CInitSock initSock;/ 为每个套节字创建一个_SOCKET_OBJ 对象typedef struct _SOCKET_OBJSOCKET s; / 套节字句柄int nOutstandingOps; / 记录此套节字上的重叠 I/O数量LPFN_ACCEPTEX lpfnAccept

3、Ex; / 扩展函数 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_ACCEPT 1#define OP_READ 2#define O

4、P_WRITE 3SOCKET 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 GetSocketObj(SOCKET s)P

5、SOCKET_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函数前需要申请PBUFFER_OBJ GetBufferObj(P

6、SOCKET_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 = :WSACreateEvent();pBuffer-pSocket = pSocket;pBuffer-

7、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;/ 释放_BUFFER_OBJ 对象的函数void FreeBufferObj(PBUFFER_OBJ pBuffer)/ 从列表中移除 BU

8、FFER_OBJ对象PBUFFER_OBJ pTest = g_pBufferHead;BOOL bFind = FALSE;if(pTest = pBuffer)g_pBufferHead = g_pBufferTail = NULL;bFind = TRUE;elsewhile(pTest != NULL if(pTest != NULL)pTest-pNext = pBuffer-pNext;if(pTest-pNext = NULL)g_pBufferTail = pTest;bFind = TRUE;/ 释放它占用的内存空间if(bFind)g_nBufferCount -;:Clo

9、seHandle(pBuffer-ol.hEvent);:GlobalFree(pBuffer-buff);:GlobalFree(pBuffer);/ 在缓冲区列表中查找_BUFFER_OBJ 对象PBUFFER_OBJ FindBufferObj(HANDLE hEvent)PBUFFER_OBJ pBuffer = g_pBufferHead;while(pBuffer != NULL)if(pBuffer-ol.hEvent = hEvent)break;pBuffer = pBuffer-pNext;return pBuffer;/ 更新事件句柄数组 g_eventsvoid Reb

10、uildArray()PBUFFER_OBJ pBuffer = g_pBufferHead;int i = 1;while(pBuffer != NULL)g_eventsi+ = pBuffer-ol.hEvent;pBuffer = pBuffer-pNext;/ 提交接收连接的_BUFFER_OBJ 对象BOOL PostAccept(PBUFFER_OBJ pBuffer)PSOCKET_OBJ pSocket = pBuffer-pSocket;if(pSocket-lpfnAcceptEx != NULL)/ 设置 I/O类型,增加套节字上的重叠 I/O计数pBuffer-nOp

11、eration = OP_ACCEPT;pSocket-nOutstandingOps +;/ 投递此重叠 I/O DWORD dwBytes;pBuffer-sAccept = :WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 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, s

12、izeof(sockaddr_in) + 16, if(!b)if(:WSAGetLastError() != WSA_IO_PENDING)return 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;WS

13、ABUF buf;buf.buf = pBuffer-buff;buf.len = pBuffer-nLen;if(:WSARecv(pBuffer-pSocket-s, return TRUE;/ 提交发送数据的_BUFFER_OBJ 对象BOOL PostSend(PBUFFER_OBJ pBuffer)/ 设置 I/O类型,增加套节字上的重叠 I/O计数pBuffer-nOperation = OP_WRITE;pBuffer-pSocket-nOutstandingOps +;/ 投递此重叠 I/ODWORD dwBytes;DWORD dwFlags = 0;WSABUF buf;b

14、uf.buf = pBuffer-buff;buf.len = pBuffer-nLen;/计算 1000以内斐波那契数列char str100=“1000以内斐波那契数列为:“;char str110;int x=0,y=1,z;for(int i=2;zpSocket-s, return TRUE;BOOL HandleIO(PBUFFER_OBJ pBuffer)PSOCKET_OBJ pSocket = pBuffer-pSocket; / 从 BUFFER_OBJ对象中提取SOCKET_OBJ对象指针,为的是方便引用pSocket-nOutstandingOps -;/ 获取重叠操作

15、结果DWORD dwTrans;DWORD dwFlags;BOOL bRet = :WSAGetOverlappedResult(pSocket-s, if(!bRet)/ 在此套节字上有错误发生,因此,关闭套节字,移除此缓冲区对象。/ 如果没有其它抛出的 I/O请求了,释放此缓冲区对象,否则,等待此套节字上的其它 I/O也完成if(pSocket-s != INVALID_SOCKET):closesocket(pSocket-s);pSocket-s = INVALID_SOCKET;if(pSocket-nOutstandingOps = 0)FreeSocketObj(pSocket

16、);FreeBufferObj(pBuffer);return FALSE;/ 没有错误发生,处理已完成的 I/Oswitch(pBuffer-nOperation)case OP_ACCEPT: / 接收到一个新的连接,并接收到了对方发来的第一个封包/ 为新客户创建一个 SOCKET_OBJ对象PSOCKET_OBJ pClient = GetSocketObj(pBuffer-sAccept);/ 为发送数据创建一个 BUFFER_OBJ对象,这个对象会在套节字出错或者关闭时释放PBUFFER_OBJ pSend = GetBufferObj(pClient, BUFFER_SIZE);i

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

18、ocket);FreeBufferObj(pSend);return 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

19、):closesocket(pSocket-s);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_SOC

20、KET):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_FLAG_OVER

21、LAPPED);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*):listen(sListen, 200);/ 为监听套节字创建一个 SOCKET_OBJ对象PSOCKET_OBJ pListen = GetSocketObj(sListen);/ 加载扩展函数 AcceptExGUID GuidAcceptEx = WSAID_ACCEPTEX;DWORD dwBytes;WSAIo

22、ctl(pListen-s, SIO_GET_EXTENSION_FUNCTION_POINTER, / 创建用来重新建立 g_events数组的事件对象g_events0 = :WSACreateEvent();/ 在此可以投递多个接受 I/O请求for(int i=0; i#include #pragma comment(lib, “WS2_32“) / 链接到 WS2_32.libclass CInitSockpublic:CInitSock(BYTE minorVer = 2, BYTE majorVer = 2)/ 初始化 WS2_32.dllWSADATA wsaData;WORD

23、 sockVersion = MAKEWORD(minorVer, majorVer);if(:WSAStartup(sockVersion, CInitSock():WSACleanup();CInitSock theSock; /加载套接字库int main()/ 创建套节字SOCKET s = :socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if(s = INVALID_SOCKET)printf(“ Failed socket() n“);return 0;/ 也可以在这里调用 bind函数绑定一个本地地址,无则系统将会自动安排/ 填写远程地址信息

24、sockaddr_in servAddr; servAddr.sin_family = AF_INET;servAddr.sin_port = htons(4567);/要连接的服务器地址servAddr.sin_addr.S_un.S_addr = inet_addr(“219.228.247.128“);if(:connect(s, (sockaddr*)return 0;/发送数据char buf = “请输出 1000以内斐波那契数列“;printf(“发送数据:%sn“,buf);send(s, buf, strlen(buf), 0);Sleep(6);/ 接收数据char buf

25、f256;int nRecv = :recv(s, buff, 256, 0);if(nRecv 0)buffnRecv = 0;printf(“接收到数据:n%sn“, buff);/ 关闭套节字:closesocket(s);return 0;执行结果:服务器端客户端:五、实验小结1. 服务器端用到的 AcceptEx 函数是从 Mswsock.lib 库导出,为了直接调用它,可以使用 WSAIoctl 函数将 AcceptEx 函数加载到内存,而不需要链接到 Mswsock.lib 库2. 由于刚开始参考书上源代码,而书上是实现回显 tcp 服务器,即将从客户端接受到的数据再发送给客户端,导致在实现代码的编写后出现客户端接收到的数据仍然为发送的数据,而服务器端则显示相应的本应发送给客户端的数据,后面对提交数据的缓冲区对象进行整体更改,将回显改为相应具体的发送要求,这也让我们小组意识到参考代码时需要仔细研究相应代码的每一个语句。六、附录网络编程技术与应用

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

当前位置:首页 > 学术论文 > 大学论文

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报