您的位置:首页 > 理论基础 > 计算机网络

实现TCP、UDP相互通信及应用

2016-10-21 10:05 501 查看
实验名称 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()也可以将整型转换成字符串。

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: