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

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

时间: 2024-10-30 09:01:52

实现TCP、UDP相互通信及应用的相关文章

高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.1.2

HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/C++.C#.Delphi.E(易语言).Java.Python 等编程语言接口.HP-Socket 对通信层实现完全封装,应用程序不必关注通信层的任何细节:HP-Socket 提供基于事件通知模型的 API 接口,能非常简单高效地整合到新旧应用程序中. 为了让使用者能方便快速地学习和使用 HP-S

高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.0.1 发布

HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/C++.C#.Delphi.E(易语言).Java.Python 等编程语言接口.HP-Socket 对通信层实现完全封装,应用程序不必关注通信层的任何细节:HP-Socket 提供基于事件通知模型的 API 接口,能非常简单高效地整合到新旧应用程序中. 为了让使用者能方便快速地学习和使用 HP-S

[Java] Tcp/udp 简单通信

本文转自  我自己的博客guozeyiblog.cn 欢迎来访 效果图: //UDP通信 import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.net.*; import javax.swing.*; class send extends JFrame implements ActionL

Socket 通信原理(Android客户端和服务器以TCP&amp;&amp;UDP方式互通)

ZERO.前言 有关通信原理内容是在网上或百科整理得到,代码部分为本人所写,如果不当,还望指教. 一.Socket通信简介 Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客户端向服务器发送请求后,服务器端才能向客户端返回数据.而Socket通信则是在双方建立起连接后就可以直接进行数据的传输,在连接时可实现信息的主动推送,而不需要每次由客户端想服务器发送请求. 那么,什么是s

PC电脑和Android模拟器访问及模拟器之间tcp/udp通信

Android系统默认只能通过IP(10.0.2.2)单向访问PC电脑,而PC电脑不能通过IP来直接访问Android模拟器系统.要想实现PC电脑和Android模拟器系统以及Android模拟器之间相互通信必须借助端口重定向(redir)来实现. 先说说端口重定向所需要的telnet客户端安装:windows:安装telnet客户端.如果没有安装,可以在windows程序管理中的打开或关闭系统功能下找到telnet客户端菜单项来启用telnet客户端功能.linux:自行安装telnet客户端

HP-SOCKET TCP/UDP通信框架库解析

项目概述: HP-SOCKET是一套通用TCP/UDP通信框架,包括服务器.客户端.Agent组件:其目标是提供高性能.通用性.简易性.可扩展.可定制: 鉴于此,其仅实现基本的通用框架通信.数据收发功能,供上层应用直接简单使用的接口实现:而对于数据包完整性和协议解析等未处理, 也就意味着需要应用层自己处理一些数据包构造或解析等操作: 事实上目前只能支持windows平台: 1. 对于TCP通信模式下:服务器端和Agent均采用的是异步IO模型中的完成端口模型,客户端采用的是就绪IO通告模型中的W

高性能 TCP &amp; UDP 通信框架 HP-Socket v3.5.1 正式发布

HP-Socket 是一套通用的高性能 TCP/UDP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#.Delphi.E(易语言).Java.Python 等编程语言接口.HP-Socket 对通信层实现完全封装,应用程序不必关注通信层的任何细节:HP-Socket 提供基于事件通知模型的 API 接口,能非常简单高效地整合到新旧应用程序中. 为了让使用者能方便快速地学习和使用 HP-Socket,迅速掌握

高性能 TCP &amp; UDP 通信框架 HP-Socket v3.2.2 正式发布

HP-Socket 是一套通用的高性能 TCP/UDP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#.Delphi.E(易语言).Java.Python 等编程语言接口.HP-Socket 对通信层实现完全封装,应用程序不必关注通信层的任何细节:HP-Socket 提供基于事件通知模型的 API 接口,能非常简单高效地整合到新旧应用程序中. 为了让使用者能方便快速地学习和使用 HP-Socket,迅速掌握

高性能 TCP &amp; UDP 通信框架 HP-Socket v3.3.1 正式发布

HP-Socket 是一套通用的高性能 TCP/UDP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#.Delphi.E(易语言).Java.Python 等编程语言接口.HP-Socket 对通信层实现完全封装,应用程序不必关注通信层的任何细节:HP-Socket 提供基于事件通知模型的 API 接口,能非常简单高效地整合到新旧应用程序中. 为了让使用者能方便快速地学习和使用 HP-Socket,迅速掌握