实验名称  Socket编程综合实验(1

  一、实验目的: 

    1、理解进程通信的原理及通信过程

    2、掌握基于TCPUDP的工作原理

    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()也可以将整型转换成字符串。

        以上是此次实验出现的主要问题,也存在其他小问题,比如地址错误、死循环等等,这些都需要仔细查看,理清思路,所有问题就会迎刃而解。