集美大学计算机工程学院实验报告课程名称:TCP/IP协议与通信程序设计班级:实验成绩:实验项目名称:基于WSAAsyncSelect模型的通信程序设计学号:上机实践日期:2016-05-12实验项目编号:08组号:1上机实践时间:2学时一、实验目的了解基于WSAAsyncSelect模型通信程序的编写,编译和执行二、实验内容与设计思想编写Win32程序模拟实现基于WSAAsyncSelect模型的两台计算机之间的通信,要求编程实现服务器端与客户端之间双向数据传递。客户端向服务器端发送“请输出从1到1000内所有的质数”,服务器回应客户端给出结果。三、实验使用环境操作系统:MicrosoftWindowsXPSP2编程环境:VisualC++6.0四、实验步骤和调试过程源代码:服务器端:#includestdio.h#includewinsock2.h#pragmacomment(lib,WS2_32)//链接到WS2_32.lib#includemath.h#defineWM_SOCKETWM_USER+101//自定义消息classCInitSock{public:CInitSock(BYTEminorVer=2,BYTEmajorVer=2){//初始化WS2_32.dllWSADATAwsaData;WORDsockVersion=MAKEWORD(minorVer,majorVer);if(::WSAStartup(sockVersion,&wsaData)!=0)return;}~CInitSock(){::WSACleanup();}};CInitSocktheSock;//加载套接字库LRESULTCALLBACKWindowProc(HWNDhWnd,UINTuMsg,WPARAMwParam,LPARAMlParam);boolisprime(intp){//判断p是否为质数intsq=(int)sqrt(p);boolflag=true;inti;for(i=2;i=sq;i++){if(p%i==0){flag=false;break;}}if(!flag&&i=sq)returnfalse;elsereturntrue;};char*getallprime(intn){//将num以内的所有质数放在同一字符串中charszprime[4096]=质数:;intlen=strlen(szprime)+strlen(,);for(inti=2;i=n;i++){if(isprime(i)){charsznum[10];itoa(i,sznum,10);char*sztemp=strcat(szprime,sznum);len+=strlen(sznum);szprime[len-1]=',';len+=strlen(,);}}//printf(%s\n,szprime);returnszprime;};intmain(){charszClassName[]=MainWClass;WNDCLASSEXwndclass;//用描述主窗口的参数填充WNDCLASSEX结构wndclass.cbSize=sizeof(wndclass);wndclass.style=CS_HREDRAW|CS_VREDRAW;wndclass.lpfnWndProc=WindowProc;wndclass.cbClsExtra=0;wndclass.cbWndExtra=0;wndclass.hInstance=NULL;wndclass.hIcon=::LoadIcon(NULL,IDI_APPLICATION);wndclass.hCursor=::LoadCursor(NULL,IDC_ARROW);wndclass.hbrBackground=(HBRUSH)::GetStockObject(WHITE_BRUSH);wndclass.lpszMenuName=NULL;wndclass.lpszClassName=szClassName;wndclass.hIconSm=NULL;::RegisterClassEx(&wndclass);//创建主窗口HWNDhWnd=::CreateWindowEx(0,szClassName,,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,NULL,NULL);if(hWnd==NULL){::MessageBox(NULL,创建窗口出错!,error,MB_OK);return-1;}USHORTnPort=4567;//此服务器监听的端口号//创建监听套节字SOCKETsListen=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);sockaddr_insin;sin.sin_family=AF_INET;sin.sin_port=htons(nPort);sin.sin_addr.S_un.S_addr=INADDR_ANY;//绑定套节字到本地机器if(::bind(sListen,(sockaddr*)&sin,sizeof(sin))==SOCKET_ERROR){printf(Failedbind()\n);return-1;}//将套接字设为窗口通知消息类型。::WSAAsyncSelect(sListen,hWnd,WM_SOCKET,FD_ACCEPT|FD_CLOSE);//进入监听模式::listen(sListen,5);//从消息队列中取出消息MSGmsg;while(::GetMessage(&msg,NULL,0,0)){//转化键盘消息::TranslateMessage(&msg);//将消息发送到相应的窗口函数::DispatchMessage(&msg);}//当GetMessage返回0时程序结束returnmsg.wParam;}LRESULTCALLBACKWindowProc(HWNDhWnd,UINTuMsg,WPARAMwParam,LPARAMlParam){switch(uMsg){caseWM_SOCKET:{//取得有事件发生的套节字句柄SOCKETs=wParam;//查看是否出错if(WSAGETSELECTERROR(lParam)){::closesocket(s);return0;}//处理发生的事件switch(WSAGETSELECTEVENT(lParam)){caseFD_ACCEPT://监听中的套接字检测到有连接进入{SOCKETclient=::accept(s,NULL,NULL);::WSAAsyncSelect(client,hWnd,WM_SOCKET,FD_READ|FD_WRITE|FD_CLOSE);}break;caseFD_WRITE:{}break;caseFD_READ:{charszText[1024]={0};if(::recv(s,szText,1024,0)==-1)::closesocket(s);else{printf(接收数据:%s,szText);char*szReply=getallprime(1000);//得到1000以内的所有质数::send(s,szReply,strlen(szReply),0);//响应客户端,回以szReply}}break;caseFD_CLOSE:{::closesocket(s);}break;}}return0;caseWM_DESTROY:::PostQuitMessage(0);return0;}//将我们不处理的消息交给系统做默认处理return::DefWindowProc(hWnd,uMsg,wParam,lParam);}客户端:#includestdio.h#includewinsock2.h#pragmacomment(lib,WS2_32)//链接到WS2_32.libclassCInitSock{public:CInitSock(BYTEminorVer=2,BYTEmajorVer=2){//初始化WS2_32.dllWSADATAwsaData;WORDsockVersion=MAKEWORD(minorVer,majorVer);if(::WSAStartup(sockVersion,&wsaData)!=0)return;}~CInitSock(){::WSACleanup();}};CInitSocktheSock;//加载套接字库intmain(){//创建套节字SOCKETs=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if(s==INVALID_SOCKET){printf(Failedsocket()\n);return0;}//也可以在这里调用bind函数绑定一个本地地址,无则系统将会自动安排//填写远程地址信息sockaddr_inservAddr;servAddr.sin_family=AF_INET;servAddr.sin_port=htons(4567);//要连接的服务器地址servAddr.sin_addr.S_un.S_addr=inet_addr(127.0.0.1);//没有联网,直接使用127.0.0.1即可if(::connect(s,(sockaddr*)&servAddr,sizeof(servAddr))==-1){printf(Failedconnect()\n);return0;}//发送数据charbuf[]=请输出从1到1000内所有的质数;printf(发送数据:%s\n,buf);send(s,buf,strlen(buf),0);Sleep(6);//接收数据charbuff[3000];intnRecv=::recv(s,buff,3000,0);if(nRecv0){buff[nRecv]='\0';printf(接收到数据:\n%s\n,buff);}//关闭套节字::closesocket(s);return0;}执行结果:服务器端:客户端:五、实验小结1.执行结果并非为质数,且出现重复经过调试分析服务器端质数放在同一字符串的函数中,发现未将分隔符号“,”的长度加进去导致整个质数的输出结果出现混乱2.客户端接收数据时发现349之后的质数未显示查看判断是否为质数及所有质数放在同一字符串中的函数时发现并没有将之后的数据隔离,反复检查发现是客户端定义接收数据的长度时由于直接利用上次实验,未将长度增大,仅为256导致后面的数据未被接收六、附录《网络编程技术与应用》