实现TCP、UDP相互通信及应用
|
实验名称 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()也可以将整型转换成字符串。 以上是此次实验出现的主要问题,也存在其他小问题,比如地址错误、死循环等等,这些都需要仔细查看,理清思路,所有问题就会迎刃而解。 |
实现TCP、UDP相互通信及应用的更多相关文章
- 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.1.1
HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...
- 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.1.2
HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...
- 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.0.1
HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...
- TCP/UDP简易通信
TCP/UDP简易通信框架源码,支持轻松管理多个TCP服务端(客户端).UDP客户端 目录 说明 TCP/UDP通信主要结构 管理多个Socket的解决方案 框架中TCP部分的使用 框架中UDP部分的 ...
- 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.1.3
HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...
- 【转】TCP/UDP简易通信框架源码,支持轻松管理多个TCP服务端(客户端)、UDP客户端
[转]TCP/UDP简易通信框架源码,支持轻松管理多个TCP服务端(客户端).UDP客户端 目录 说明 TCP/UDP通信主要结构 管理多个Socket的解决方案 框架中TCP部分的使用 框架中UDP ...
- TCP/UDP简易通信框架源码,支持轻松管理多个TCP服务端(客户端)、UDP客户端
目录 说明 TCP/UDP通信主要结构 管理多个Socket的解决方案 框架中TCP部分的使用 框架中UDP部分的使用 框架源码结构 补充说明 源码地址 说明 之前有好几篇博客在讲TCP/UDP通信方 ...
- linux 网络编程:客户端与服务器通过TCP协议相互通信 + UDP
1.TCP编程的客户端一般步骤: 1.创建一个socket,用函数socket(): 2.设置socket属性,用函数setsockopt():* 可选: 3.绑定IP地址.端口等信息到socket上 ...
- [Java] Tcp/udp 简单通信
本文转自 我自己的博客guozeyiblog.cn 欢迎来訪 效果图: //UDP通信 import java.awt.*; import java.awt.event.ActionEvent; i ...
随机推荐
- RHEL7修改swappiness
linux系统swappiness参数在内存与交换分区间优化 2014-08-14 10:24:19分类: Linux swappiness的值的大小对如何使用swap分区是有着很大的联系的.swap ...
- Java泛型学习笔记 - (四)有界类型参数
1. 当我们希望对泛型的类型参数的类型进行限制的时候(好拗口), 我们就应该使用有界类型参数(Bounded Type Parameters). 有界类型参数使用extends关键字后面接上边界类型来 ...
- strace命令使用
在调试的时候,strace能帮助你追踪到一个程序所执行的系统调用.当你想知道程序和操作系统如何交互的时候,这是极其方便的,比如你想知道执行了哪些系统调用,并且以何种顺序执行. 这个简单而又强大的工具几 ...
- svn co
svn co 的用法经常有两种: 第一种: 直接 svn co http://svnserver/mypro/trunk 此时, 会在你的当前目录 ...
- JavaScript测试题
您的回答: 1.我们可以在下列哪个 HTML 元素中放置 Javascript 代码? 您的回答:<script> 2.写 "Hello World" 的正确 Java ...
- 解决MySQL数据库不允许从远程访问的方法
授权法.例如,你想myuser使用mypassword从任何主机连接到mysql服务器的话. mysql>GRANT ALL PRIVILEGES ON *.* TO 'myuser'@'%' ...
- 用css实现条纹背景
我先额外的说一下怎么用CSS绘制三角形: 绘制三角形是把边框加粗,将元素的宽高都设为0,让其余的边框颜色透明,下面我们来看实现的代码: 先把边框的颜色设置成不同颜色: #div{ border-col ...
- CCF 201612-2 工资计算 java 解题
问题描述 小明的公司每个月给小明发工资,而小明拿到的工资为交完个人所得税之后的工资.假设他一个月的税前工资(扣除五险一金后.未扣税前的工资)为S元,则他应交的个人所得税按如下公式计算: 1) 个人所得 ...
- entity framework 新手入门篇(2)-entity framework基本的增删改查
经过前两节的简单描述,终于可以进入entity framework的使用部分了.本节将对entity framework原生的增删改查进行讲解. 承接上面的部分,我们有一个叫做House的数据库,其中 ...
- django个人总结
今天是周末,多写写吧,和大家分享交流一下,虽园子django使用者不多,但算作自己的自我提升吧 django的网站建站的一点点自己的建议. 1:隐藏自己的前端行为或者能后端做的尽量不要在前端进行. 如 ...

