实验名称 Socket编程综合实验(1) 一、实验目的: 1、理解进程通信的原理及通信过程 2、掌握基于TCP和UDP的工作原理 3、掌握基本的Socket网络编程原理及方法 二、实验内容 1、掌握简单的基于流式套接字的编程技术:如实现简单的聊天功能、实现简单的信息服务功能等等。 2、掌握简单的基于数据报式套接字的编程技术:如实现简单的聊天功能、实现简单的信息服务功能等等。 三、对所实现的功能进行描述,并附上相应的流程图。 1、基于流式套接字:可以通过选择,分别实现聊天、游戏:猜数字和应用:判断是否为闰年功能。 2、基于数据报式套接字:可以通过选择,分别实现聊天、游戏:猜数字和应用:判断是否为闰年功能。
TCP实验流程图:
|
TCP客户端 TCP服务器端
UDP实验流程图: UDP客户端 UDP服务器端
四、实验源代码:(关键接口函数和代码必须加注释) 基于流式套接字TCP源代码: Initsock.h文件: #pragma comment(lib,"WS2_32.lib")
class CinitSock { public: CinitSock(BYTE minorVer = 2, BYTE majorVer = 2) { // 初始化WS2_32.dll WSADATA wsaData; WORD sockVersion = MAKEWORD(minorVer, majorVer); if(::WSAStartup(sockVersion, &wsaData) != 0) { exit(0); } } ~CinitSock() { ::WSACleanup(); } };
TCPClient.cpp文件: #include"initsock.h" #include<stdio.h> #include<iostream> #include<string> #include<time.h> CinitSock initsock; #define BUF_SIZE 1024
int main() { SOCKET sHost; //与服务器进行通信的socket sockaddr_in servAddr; //服务器地址 char buf[BUF_SIZE]; //用于接受客户端数据的缓冲区 int retVal; //调用各种socket函数的返回值 printf("*****************************************\n"); printf(" 客户端 \n"); printf("*****************************************\n"); //###################创建TCP套接字############################## sHost = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(sHost == INVALID_SOCKET) { printf("socket error!\n"); WSACleanup(); return -1; } // 也可以在这里调用bind函数绑定一个本地地址 // 否则系统将会自动安排 // 填写远程地址信息 servAddr.sin_family = AF_INET; servAddr.sin_port = htons(9990); // 注意,这里要填写服务器程序(TCPServer程序)所在机器的IP地址 // 如果你的计算机没有联网,直接使用127.0.0.1即可 servAddr.sin_addr.S_un.S_addr = inet_addr("10.115.5.62");
//######################连接服务器############################### retVal = connect(sHost,(LPSOCKADDR)&servAddr,sizeof(servAddr)); if(SOCKET_ERROR==retVal) { printf(" Failed connect!\n"); closesocket(sHost); WSACleanup(); return -1; } printf("连接成功,可以进行通信! \n");
//#########循环向服务器发送字符串,并接收服务器回复的信息########### char c; printf("请选择功能:C.聊天(Chat) G.游戏:猜数字(Game) L.应用:判断是否为闰年(Leap year):\n"); scanf("%c",&c); switch(c) { case'C': { //####################聊天功能################## printf("欢迎您!您可以开始聊天啦!\n"); printf("请先输入C:\n"); char buf1[BUF_SIZE]; scanf("%s",&buf1); send(sHost,buf1,BUF_SIZE,0); //向服务器发送数据 while(true) { //向服务器发送数据 printf("请向服务器发送数据:"); char buf2[BUF_SIZE]; scanf("%s",&buf2); //接收输入的数据 retVal=send(sHost,buf2,BUF_SIZE,0);//向服务器端发送数据 ZeroMemory(buf2,BUF_SIZE); //清空发送数据的缓冲区 if(SOCKET_ERROR == retVal) { printf("Failed send! \n"); closesocket(sHost); WSACleanup(); return 1; }
//获取当前系统时间 SYSTEMTIME st; GetLocalTime(&st); char sDateTime[30]; sprintf(sDateTime,"%4d-%2d-%2d %2d:%2d:%2d",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond); //接收服务器回传的数据 ZeroMemory(buf,BUF_SIZE);//清空接收数据的缓冲区 retVal=recv(sHost,buf,sizeof(buf)+1,0); printf("%s,收到来自服务器的数据[%s:%d] :%s\n",sDateTime, inet_ntoa(servAddr.sin_addr),servAddr.sin_port,buf); //如果收到“quit”,则退出 if(strcmp(buf,"quit")==0) { retVal=send(sHost,"quit",strlen("quit"),0); break; } }break; }break;
case'G': { //######################游戏功能####################### printf("欢迎您!您可以开始游戏啦!\n"); printf("请先输入G:\n"); char buf3[BUF_SIZE]; scanf("%s",&buf3); send(sHost,buf3,BUF_SIZE,0); printf("请输入一个1~1000之间的数:\n"); while(true) { char buf4[BUF_SIZE]; int m; scanf("%d",&m); itoa(m, buf4, 10);//sprintf(buf4,"%d",m)与itoa()同义 retVal=send(sHost,buf4,BUF_SIZE,0);//向服务器端发送数字 if(SOCKET_ERROR == retVal) { printf("Failed send! \n"); closesocket(sHost); WSACleanup(); return 1; } //获取当前系统时间 SYSTEMTIME st; GetLocalTime(&st); char sDateTime[30]; sprintf(sDateTime,"%4d-%2d-%2d %2d:%2d:%2d",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond); //接收服务器回传的数据 ZeroMemory(buf,BUF_SIZE);//清空接收数据的缓冲区 retVal=recv(sHost,buf,sizeof(buf)+1,0);//接收数据 printf("%s,收到来自服务器的数据[%s:%d] :%s\n", sDateTime, inet_ntoa(servAddr.sin_addr),servAddr.sin_port,buf); //如果收到“0”,则退出 if(strcmp(buf,"0")==0) { retVal=send(sHost,"0",strlen("0"),0); break; } } } case'L': { //################应用:判断是否为闰年ê################ printf("欢迎您!您可以开始应用啦!\n"); printf("请先输入L:\n"); char buf5[1024]; scanf("%s",&buf5); //接收输入的数据 retVal=send(sHost,buf5,1024,0); //向服务器端发送数据 while(true) { char year[1024]; int y; printf("请输入年份:\n"); scanf("%d",&y); //接收输入的数据 itoa(y, year, 10);// sprintf(year,"%d",y);//将输入的十进制数转换成字符串存储在缓冲区year中 retVal=send(sHost,year,1024,0); //向服务器端发送年份 ZeroMemory(year,1024); //清空发送数据的缓冲区 if(SOCKET_ERROR == retVal) { printf("Failed send! \n"); closesocket(sHost); WSACleanup(); return 1; }
//获取当前系统时间 SYSTEMTIME st; GetLocalTime(&st); char sDateTime[30]; sprintf(sDateTime,"%4d-%2d-%2d %2d:%2d:%2d",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond); //接收服务器回传的数据 ZeroMemory(buf,BUF_SIZE);//清空接收数据的缓冲区 retVal=recv(sHost,buf,sizeof(buf)+1,0);//接收数据 printf("%s,收到来自服务器的数据[%s:%d] :%s\n", sDateTime, inet_ntoa(servAddr.sin_addr),servAddr.sin_port,buf); //如果收到“0”,则退出 if(strcmp(buf,"0")==0) { retVal=send(sHost,"0",strlen("0"),0); break; } } } } printf("正在关闭socket...\n"); //释放资源 closesocket(sHost); WSACleanup(); //暂停,按任意键退出 system("pause"); return 0; } TCPServer.cpp
#include"initsock.h" #include<stdio.h> #include<iostream> #include<string> # include<time.h> #define BUF_SIZE 1024 CinitSock initsock; // 初始化Winsock库
int main() { SOCKET sListen; //服务器socket,用于监听客户端请求 SOCKET sClient; //客户端socket,用于实现与客户端的通信 int retVal; //调用各种socke函数的返回值 char buf[BUF_SIZE]; //用于接受客户端数据的缓冲区 printf("*****************************************\n"); printf(" 服务器端 \n"); printf("*****************************************\n");
// ####################创建TCP套节字####################### sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(sListen == INVALID_SOCKET) { printf("socket error! \n"); WSACleanup(); return -1; } //指定绑定的地址 struct sockaddr_in addrServ; //定义服务器地址 addrServ.sin_family=AF_INET; addrServ.sin_port = htons(9990); addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //绑定到socket retVal=bind(sListen,(const struct sockaddr*)&addrServ,sizeof(SOCKADDR_IN)); if(SOCKET_ERROR == retVal) { printf("Failed bind! \n"); closesocket(sListen); WSACleanup(); return -1; } // #########################进入监听模式####################### retVal=listen(sListen,1); if(SOCKET_ERROR == retVal) { printf("Failed listen! \n"); closesocket(sListen); WSACleanup(); return -1; }
// ####################接受客户端的连接请求ó######################### printf("TCP Server start...\n"); sockaddr_in addrclient; //客户端地址 int addrclientlen = sizeof(addrclient); // 接受一个新连接 sClient = accept(sListen, (sockaddr FAR*)&addrclient, &addrclientlen); if(sClient == INVALID_SOCKET) { printf("Failed accept!?"); closesocket(sListen); WSACleanup(); return -1; } printf("连接成功,可以进行通信! \n"); //################循环接受客户端的数据,并向客户端发送数据Y######################### ZeroMemory(buf,BUF_SIZE); //清空接收数据的缓冲区 retVal=recv(sClient,buf,BUF_SIZE,0); if(SOCKET_ERROR == retVal) { printf("Failed recv! \n"); closesocket(sListen); closesocket(sClient); WSACleanup(); return -1; } if(strcmp(buf,"C")==0) { //#######################聊天功能########################## printf("对方想要和你聊天!\n"); while(true) { ZeroMemory(buf,BUF_SIZE); //清空接收数据的缓冲区 retVal=recv(sClient,buf,BUF_SIZE,0); if(SOCKET_ERROR == retVal) { printf("Failed recv! \n"); closesocket(sListen); closesocket(sClient); WSACleanup(); return -1; }
//获取当前系统时间 SYSTEMTIME st; GetLocalTime(&st); char sDateTime[30]; sprintf(sDateTime,"%4d-%2d-%2d %2d:%2d:%2d",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond); //打印输出的信息 printf("%s,收到来自客户端的数据 [%s:%d] :%s\n",sDateTime, inet_ntoa(addrclient.sin_addr),addrclient.sin_port,buf); //如果收到“quit”字符串,则退出 if(strcmp(buf,"quit")==0) { retVal=send(sClient,"quit",strlen("quit"),0); break; }
//向客户端发送数据 printf("请向客户端发送数据:"); std::string str; //接收输入的数据 std::getline(std::cin,str); //将用户输入的信息复制到buf中 ZeroMemory(buf,BUF_SIZE); //清空发送数据的缓冲区 strcpy(buf,str.c_str()); //向客户端发送数据 retVal=send(sClient,buf,strlen(buf),0); //向客户端发送回显字符串 if(SOCKET_ERROR == retVal) { printf("Failed send! \n"); closesocket(sClient); WSACleanup(); return -1; } } } if(strcmp(buf,"G")==0) { //##################游戏功能############################## printf("对方想要开始游戏!\n"); int num; srand(time(NULL)); num=1+(rand()%1000); //随机产生一个整数 printf("随机产生一个数:%d\n",num);
while(true) { ZeroMemory(buf,BUF_SIZE); //清空接收数据的缓冲区 retVal=recv(sClient,buf,BUF_SIZE,0);//接收来自客户端的数据 if(SOCKET_ERROR == retVal) { printf("Failed recv! \n"); closesocket(sListen); closesocket(sClient); WSACleanup(); return -1; } //获取当前系统时间 SYSTEMTIME st; GetLocalTime(&st); char sDateTime[30]; sprintf(sDateTime,"%4d-%2d-%2d %2d:%2d:%2d",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond); //打印输出的信息 printf("%s,收到来自客户端的数据[%s:%d] :%s\n",sDateTime, inet_ntoa(addrclient.sin_addr),addrclient.sin_port,buf); //如果收到“0”,则退出 if(strcmp(buf,"0")==0) { retVal=send(sClient,"0",strlen("0"),0); break; }
char buf0[BUF_SIZE]="太棒了!你已经猜到已了正确的数!结束游戏请输入0\n"; char buf2[BUF_SIZE]="太低了,请重新输入一个1~1000之间的数:\n"; char buf3[BUF_SIZE]="太高了,请重新输入一个1~1000之间的数:\n"; int n; n = atoi(buf);//将缓冲区接收到的字符串转成整型 if(num==n) { //向客户端发送数据 retVal=send(sClient,buf0,strlen(buf0),0); //向客户端发送回显字符串 if(SOCKET_ERROR == retVal) { printf("Failed send! \n"); closesocket(sClient); WSACleanup(); return -1; } } else if(n<num) { retVal=send(sClient,buf2,strlen(buf2),0); //向客户端发送回显字符串 if(SOCKET_ERROR == retVal) { printf("Failed send! \n"); closesocket(sClient); WSACleanup(); return -1; } } else { retVal=send(sClient,buf3,strlen(buf3),0); //向客户端发送回显字符串 ZeroMemory(buf3,BUF_SIZE); //清空发送数据的缓冲区 if(SOCKET_ERROR == retVal) { printf("Failed send! \n"); closesocket(sClient); WSACleanup(); return -1; } } } } if(strcmp(buf,"L")==0) { printf("对方想实现应用:判断年份是否为闰年!\n"); while(true) { ZeroMemory(buf,BUF_SIZE); //清空接收数据的缓冲区 retVal=recv(sClient,buf,BUF_SIZE,0);//接收来自客户端的数据 if(SOCKET_ERROR == retVal) { printf("Failed recv! \n"); closesocket(sListen); closesocket(sClient); WSACleanup(); return -1; } //获取当前系统时间 SYSTEMTIME st; GetLocalTime(&st); char sDateTime[30]; sprintf(sDateTime,"%4d-%2d-%2d %2d:%2d:%2d",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond); //打印输出的信息 printf("%s,收到来自客户端的数据[%s:%d] :%s\n",sDateTime, inet_ntoa(addrclient.sin_addr),addrclient.sin_port,buf); //如果收到“0”,则退出 if(strcmp(buf,"0")==0) { retVal=send(sClient,"0",strlen("0"),0); break; } char buf1[1024]="是闰年!\n"; char buf2[1024]="不是闰年!\n"; int year; year = atoi(buf); //判断是否为闰年 if(year%4==0 && year%100!=0 || year%400==0) { retVal=send(sClient,buf1,strlen(buf1),0); //向客户端发送回显字符串 if(SOCKET_ERROR == retVal) { printf("Failed send! \n"); closesocket(sClient); WSACleanup(); return -1; } } else { retVal=send(sClient,buf2,strlen(buf2),0); //向客户端发送回显字符串 if(SOCKET_ERROR == retVal) { printf("Failed send! \n"); closesocket(sClient); WSACleanup(); return -1; } } } } //释放socket printf("正在关闭socket...\n"); closesocket(sListen); closesocket(sClient); WSACleanup(); //暂停,按任意键退出 system("pause"); return 0; }
基于数据报式套接字UDP源代码: UDPClient.cpp #include<WINSOCK2.H> #include<iostream> #include<string> #include <tchar.h> #pragma comment(lib,"WS2_32.lib")
int _tmain(int argc, _TCHAR* argv[]) { WSADATA wsaData; //WSADATA变量,用于初始化Windows Socket SOCKET SendSocket; //发送消息的socket //接收消息的socket sockaddr_in RecvAddr; //服务器端地址 sockaddr_in SenderAddr; //发送者的地址 int port = 27015; //服务器端监听地址 int BufLen=1024; //缓冲区大小 int retVal; //调用各种socket函数的返回值 int SenderAddrSize=sizeof(SenderAddr); printf("*****************************************\n"); printf(" 客户端 \n"); printf("*****************************************\n"); //###################初始化socket############################ WSAStartup(MAKEWORD(2,2),&wsaData); //创建接收数据报的socket SendSocket=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(INVALID_SOCKET==SendSocket) { printf(" socket error! \n"); WSACleanup(); return -1; } //########################设置服务器地址####################### RecvAddr.sin_family=AF_INET; RecvAddr.sin_port = htons(27015); RecvAddr.sin_addr.S_un .S_addr = inet_addr("127.0.0.1"); //###########################向服务器发送、接收数据报################# printf("正在向服务器发送数据...\n");
char c; printf("请选择功能:C.聊天(Chat) G.游戏:猜数字(Game) L.应用:判断是否为闰年(Leap year):\n"); scanf("%c",&c); switch(c) { case'C': { //#########################聊天功能##################### printf("欢迎您!您可以开始聊天啦!\n"); printf("请先输入C:\n"); char buf1[1024]; scanf("%s",&buf1); //接收输入的数据 retVal=sendto(SendSocket,buf1,1024,0,(SOCKADDR *)&RecvAddr,sizeof(RecvAddr));//向服务器发送一个C while(true) { //向服务器发送数据 printf("请向服务器发送数据:"); char buf2[1024]; scanf("%s",&buf2); //接收输入的数据 //向服务器发送数据 retVal=sendto(SendSocket,buf2,1024,0,(SOCKADDR *)&RecvAddr,sizeof(RecvAddr)); ZeroMemory(buf2,1024); //清空发送数据的缓冲区 if(SOCKET_ERROR == retVal) { printf("Failed send! \n"); closesocket(SendSocket); WSACleanup(); return 1; } char SendBuf2[1024]; //获取当前系统时间 SYSTEMTIME st; GetLocalTime(&st); char sDateTime[30]; sprintf(sDateTime,"%4d-%2d-%2d %2d:%2d:%2d",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond); //接收服务器回传的数据 ZeroMemory(SendBuf2,1024); //清空接收数据的缓冲区 retVal=recvfrom(SendSocket,SendBuf2,BufLen,0,(SOCKADDR *)&SenderAddr,&SenderAddrSize); printf("%s,收到来自服务器端的数据[%s:%d] :%s\n", sDateTime, inet_ntoa(SenderAddr.sin_addr),SenderAddr.sin_port,SendBuf2); //如果收到“quit”,则退出 if(strcmp(SendBuf2,"quit")==0) { retVal = send(SendSocket,"quit",strlen("quit"),0); break; } }break; }
case'G': { //#####################游戏功能##################### printf("欢迎您!您可以开始游戏啦!\n"); printf("请先输入G:\n"); char buf3[1024]; scanf("%s",&buf3); retVal=sendto(SendSocket,buf3,1024,0,(SOCKADDR *)&RecvAddr,sizeof(RecvAddr));//向服务器发送一个G printf("请输入一个1~1000之间的数:\n"); while(true) { char buf4[1024]; int m; scanf("%d",&m); itoa(m, buf4, 10);//sprintf(buf4,"%d",m);与itoa()同义 retVal=sendto(SendSocket,buf4,1024,0,(SOCKADDR *)&RecvAddr,sizeof(RecvAddr)); ZeroMemory(buf4,1024); //清空发送数据的缓冲区 if(SOCKET_ERROR == retVal) { printf("Failed send! \n"); closesocket(SendSocket); WSACleanup(); return 1; } char SendBuf2[1024]; //获取当前系统时间 SYSTEMTIME st; GetLocalTime(&st); char sDateTime[30]; sprintf(sDateTime,"%4d-%2d-%2d %2d:%2d:%2d",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond); //接收服务器回传的数据 ZeroMemory(SendBuf2,1024); //清空接收数据的缓冲区 retVal=recvfrom(SendSocket,SendBuf2,BufLen,0,(SOCKADDR *)&SenderAddr,&SenderAddrSize); printf("%s,接收到来自服务器端的数据[%s:%d] :%s\n",sDateTime, inet_ntoa(SenderAddr.sin_addr),SenderAddr.sin_port,SendBuf2); //如果收到“0”,则退出 if(strcmp(SendBuf2,"0")==0) { retVal = send(SendSocket,"0",strlen("0"),0); break; } } } case'L': { //###############应用:判断是否为闰年############## printf("欢迎您!您可以开始应用啦!\n"); printf("请先输入L?:\n"); char buf6[1024]; scanf("%s",&buf6); //接收输入的数据 //向服务器发送数据 retVal=sendto(SendSocket,buf6,1024,0,(SOCKADDR *)&RecvAddr,sizeof(RecvAddr)); while(true) { char year[1024]; int y; printf("请输入年份:\n"); scanf("%d",&y); //接收输入的数据 sprintf(year,"%d",y);//itoa(y, year, 10); //将输入的十进制数转换成字符串存储在缓冲区year中 retVal=sendto(SendSocket,year,1024,0,(SOCKADDR *)&RecvAddr,sizeof(RecvAddr)); ZeroMemory(year,1024); //清空发送数据的缓冲区 if(SOCKET_ERROR == retVal) { printf("Failed send! \n"); closesocket(SendSocket); WSACleanup(); return 1; }
//获取当前系统时间 SYSTEMTIME st; GetLocalTime(&st); char sDateTime[30]; sprintf(sDateTime,"%4d-%2d-%2d %2d:%2d:%2d",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond); //接收服务器回传的数据 char SendBuf2[1024]; ZeroMemory(SendBuf2,1024);//清空接收数据的缓冲区 retVal=recvfrom(SendSocket,SendBuf2,BufLen,0,(SOCKADDR *)&SenderAddr,&SenderAddrSize); printf("%s,收到来自服务器端的数据[%s:%d] :%s\n",sDateTime, inet_ntoa(SenderAddr.sin_addr),SenderAddr.sin_port,SendBuf2); } } } //发送完成,关闭socket printf("正在关闭socket...\n"); closesocket(SendSocket); // 释放资源,并退出 printf("退出!"); WSACleanup(); return 0; } UDPServer.cpp #include<WINSOCK2.H> #include<iostream> #include<string> #include <tchar.h> #include<time.h> #pragma comment(lib,"WS2_32.lib")
int _tmain(int argc, _TCHAR* argv[]) { WSADATA wsaData; //WSADATA变量,用于初始化Windows Socket SOCKET RecvSocket; //接收消息的socket//发送消息的socket sockaddr_in RecvAddr; //服务器端地址 sockaddr_in SenderAddr; //发送者的地址 int port = 27015; //服务器端监听地址 char RecvBuf[1024]; //接收数据的缓冲区 int BufLen=1024; //缓冲区大小 int retVal; //调用各种socket函数的返回值 int SenderAddrSize=sizeof(SenderAddr); printf("*****************************************\n"); printf(" 服务器端 \n"); printf("*****************************************\n"); //#########################初始化socket######################## WSAStartup(MAKEWORD(2,2),&wsaData); //创建接收数据报的socket RecvSocket=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if( INVALID_SOCKET == RecvSocket) { printf("socket error! \n"); WSACleanup(); return -1; } //#############将socket与指定端口0.0.0.0绑定################### RecvAddr.sin_family=AF_INET; RecvAddr.sin_port = htons(27015); RecvAddr.sin_addr .S_un .S_addr=inet_addr("127.0.0.1"); retVal=bind(RecvSocket,(SOCKADDR *)&RecvAddr,sizeof(RecvAddr)); if(SOCKET_ERROR == retVal) { printf("Failed bind! \n"); closesocket(RecvSocket); WSACleanup(); return -1; } printf("正y在ú接ó收?数簓据Y...\n"); //#############循环向客户端接收、发送的数据################### //调用recvfrom()函数在绑定的socke上接收数据 retVal=recvfrom(RecvSocket,RecvBuf,BufLen,0,(SOCKADDR *)&SenderAddr,&SenderAddrSize); if(retVal == INVALID_SOCKET) { printf("Failed recvfrom!"); closesocket(RecvSocket); WSACleanup(); return -1; } //################################聊天功能####################### if(strcmp(RecvBuf,"C")==0) { printf("对方想要和你聊天!\n"); while(true) { ZeroMemory(RecvBuf,1024); //清空接收数据的缓冲区 //调用recvfrom()函数在绑定的socket上接数据 retVal=recvfrom(RecvSocket,RecvBuf,BufLen,0,(SOCKADDR *)&SenderAddr,&SenderAddrSize); if(retVal == INVALID_SOCKET) { printf("Failed recvfrom!"); closesocket(RecvSocket); WSACleanup(); return -1; } //获取当前系统时间 SYSTEMTIME st; GetLocalTime(&st); char sDateTime[30]; sprintf(sDateTime,"%4d-%2d-%2d %2d:%2d:%2d",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond); //打印输出的信息 printf("%s,收到来自客户端的数据 [%s:%d] :%s\n",sDateTime, inet_ntoa(SenderAddr.sin_addr),SenderAddr.sin_port,RecvBuf); //如果收到“quit”,则退出 if(strcmp(RecvBuf,"quit") == 0) { retVal = send(RecvSocket,"quit",strlen("quit"),0); break; } //向客户端发送数据 char RecvBuf2[1024]; printf("请向客户端发送数据:"); std::string str; //接收输入的数据 std::getline(std::cin,str); //将用户输入的信息复制到buf中 strcpy(RecvBuf2,str.c_str()); retVal=sendto(RecvSocket,RecvBuf2,BufLen,0,(SOCKADDR *)&SenderAddr,sizeof(SenderAddr)); ZeroMemory(RecvBuf2,1024); //清空发送数据的缓冲区 if(SOCKET_ERROR == retVal) { printf("Failed send! \n"); closesocket(RecvSocket); WSACleanup(); return -1; } } }
if(strcmp(RecvBuf,"G")==0) { //###################游戏功能########################### printf("对方想要开始游戏!\n"); int num; srand(time(NULL)); num=1+(rand()%1000); //随机产生一个整数 printf("随机产生一个数:%d\n",num);
while(true) { ZeroMemory(RecvBuf,1024); //清空接收数据的缓冲区 //调用recvfrom()函数在绑定的socke上接收数据 retVal=recvfrom(RecvSocket,RecvBuf,BufLen,0,(SOCKADDR *)&SenderAddr,&SenderAddrSize); if(retVal == INVALID_SOCKET) { printf("Failed recvfrom!"); closesocket(RecvSocket); WSACleanup(); return -1; } //获取当前系统时间 SYSTEMTIME st; GetLocalTime(&st); char sDateTime[30]; sprintf(sDateTime,"%4d-%2d-%2d %2d:%2d:%2d",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond); //打印输出的信息 printf("%s,收到来自客户端的数据[%s:%d] :%s\n",sDateTime, inet_ntoa(SenderAddr.sin_addr),SenderAddr.sin_port,RecvBuf); //如果收到“0”,则退出 if(strcmp(RecvBuf,"0") == 0) { retVal = send(RecvSocket,"0",strlen("0"),0); break; } char buf0[1024]="太棒了!你已经猜到已了正确的数!结束游戏请输入0\n"; char buf2[1024]="太低了,重新输入一个1~1000之间的数:\n"; char buf3[1024]="太高了,重新输入一个1~1000之间的数:\n";
int n; n = atoi(RecvBuf);//将缓冲区接收到的字符串转成整型 if(num==n) { //向客户端发送数据 retVal=sendto(RecvSocket,buf0,BufLen,0,(SOCKADDR *)&SenderAddr,sizeof(SenderAddr)); ZeroMemory(buf0,1024); //清空发送数据的缓冲区 if(SOCKET_ERROR == retVal) { printf("Failed send! \n"); closesocket(RecvSocket); WSACleanup(); return -1; } } else if(n<num) { retVal=sendto(RecvSocket,buf2,BufLen,0,(SOCKADDR *)&SenderAddr,sizeof(SenderAddr)); ZeroMemory(buf2,1024); //清空发送数据的缓冲区 if(SOCKET_ERROR == retVal) { printf("Failed send! \n"); closesocket(RecvSocket); WSACleanup(); return -1; } } else { retVal=sendto(RecvSocket,buf3,BufLen,0,(SOCKADDR *)&SenderAddr,sizeof(SenderAddr)); ZeroMemory(buf3,1024); if(SOCKET_ERROR == retVal) { printf("Failed send! \n"); closesocket(RecvSocket); WSACleanup(); return -1; } } } } //###################应用:判断是否为闰年################# if(strcmp(RecvBuf,"L")==0) { printf("对方想实现应用:判断年份是否为闰年!\n"); while(true) { ZeroMemory(RecvBuf,1024); //调用recvfrom()函数在绑定的socket上接收数据 retVal=recvfrom(RecvSocket,RecvBuf,BufLen,0,(SOCKADDR *)&SenderAddr,&SenderAddrSize); if(retVal == INVALID_SOCKET) { printf("Failed recvfrom!"); closesocket(RecvSocket); WSACleanup(); return -1; } //获取当前系统时间 SYSTEMTIME st; GetLocalTime(&st); char sDateTime[30]; sprintf(sDateTime,"%4d-%2d-%2d %2d:%2d:%2d",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond); //打印输出的信息 printf("%s,收到来自客户端的数据[%s:%d] :%s\n",sDateTime, inet_ntoa(SenderAddr.sin_addr),SenderAddr.sin_port,RecvBuf); //如果收到“0”,则退出 if(strcmp(RecvBuf,"0") == 0) { retVal = send(RecvSocket,"0",strlen("0"),0); break; }
char buf1[1024]="是?闰è?年ê!?\n"; char buf2[1024]="不?是?闰è?年ê!?\n"; int year; year = atoi(RecvBuf);
//判断是否为闰年 if(year%4==0 && year%100!=0 || year%400==0) { retVal=sendto(RecvSocket,buf1,BufLen,0,(SOCKADDR *)&SenderAddr,sizeof(SenderAddr)); //向客户端发送回显字符串 if(SOCKET_ERROR == retVal) { printf("Failed send! \n"); closesocket(RecvSocket); WSACleanup(); return -1; } } else { retVal=sendto(RecvSocket,buf2,BufLen,0,(SOCKADDR *)&SenderAddr,sizeof(SenderAddr));//向客户端发送回显字符串 if(SOCKET_ERROR == retVal) { printf("Failed send! \n"); closesocket(RecvSocket); WSACleanup(); return -1; } } } } //关闭socket,结束接收数据 printf("正在关闭socket...\n"); closesocket(RecvSocket); //释放资源,退出 printf("退出!"); WSACleanup(); return 0; }
五、实验总结与心得: 本次实验聊天功能比较容易实现,编写游戏和应用时出现了很多问题,如下: 1.发送数据后会收到很多“烫”。解决办法:在发送后,接收前都加上ZeroMemory(),清空缓冲区,就不会发生字符串溢出的现象;另外,如果将ZeroMemory()放在了send()之前,就会清空输入的内容,接收到的消息则为空,如果将ZeroMemory()放在recv()之后,就会清空接收到的内容,无法对此数据进行接下来的操作。 2.进行游戏:猜数字时,只能判断一次,第二次不能输出结果。解决办法:仔细梳理流程,就会发现因为在服务器端的if语句前多加了一个循环体while,导致第二次无法正常接收语句。 3.使用int _tmain(int argc, _TCHAR* argv[])时,要加上语句#include<time.h>。 4.在游戏和应用中出现字符串和整型之间的相互转换问题。解决办法:用itoa()将整型转成字符串,再发送数据;用atoi()将字符串转成整型,再进行接下来的操作。Sprintf()也可以将整型转换成字符串。 以上是此次实验出现的主要问题,也存在其他小问题,比如地址错误、死循环等等,这些都需要仔细查看,理清思路,所有问题就会迎刃而解。
|