代码
Server:
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "WS2_32") // 链接到WS2_32.lib
#include <stdlib.h>
#include <ctime>//随机数头文件
这是两个函数!一个是srand函数!这是在调用rand ()这个函数之前使用的! rand()是一个产生随机数的函数!而srand是一个设置随机数种子的函数! 通常这两个函数是一起使用的!来完成产生随机数的功能! 而time(NULL)这个函数的返回值是作为srand函数的参数的!意思是以现在的系统时间作为随机数的种子来产生随机数!至于NULL这个参数。只有设置成NULL才能获得系统的时间!
生成随机数据,模拟采集的设备信息
int Rand()
{ srand(time(NULL));
int j ;
j = rand()%1015448481651 ;
return j;
}
char buff[1000]={0};
此函数用来生成模拟设备信息的函数
char *creat()
{
int num=Rand(); //将生成的随机数,传给sum
char *translate=(char *)malloc(1000);//向系统申请一个堆空间,malloc的返回值类型是void*,需要用(char*)来强转类型以和等号左边匹配
memset(translate,0,1000); //清空这个区域
char m[100]={0};
sprintf(m,"%d",num); //把格式化的数据写入某个字符串缓冲区
memcpy(buff,m,sizeof(buff));
printf("采集到的数据%s\n\n", buff);//以字符串形式打印输出变量str后光标换行
return(buff);
}
void main()
{
printf("TCP服务器(采集点)\n\n\n\n");
SOCKET sock1,sock2;
WSADATA wsadata;
struct sockaddr_in sai;
int count;
//地址初始化
sai.sin_family = AF_INET;
sai.sin_port = htons(4777);
sai.sin_addr.s_addr = inet_addr("127.0.0.1");
//连接
printf("================等待客户端启动==================\n");
printf("\n\n\n\n");
WSAStartup(MAKEWORD(1,1),&wsadata);//加载套接字库和版本协商
sock1=socket(AF_INET,SOCK_STREAM,0);
bind(sock1,(struct sockaddr*)&sai,sizeof(sai));
listen(sock1,2);
count=sizeof(sai);
sock2=accept(sock1,(struct sockaddr*)&sai,&count);//接收并保存客户端信息
printf("=============已与客户端连接========================\n");
for( int i=0;i<5;i++)
{
*creat();
send(sock2,buff,sizeof(buff),0);
Sleep(2000);
}
closesocket(sock1);
closesocket(sock2);
WSACleanup();
printf("\n=====================关闭========================\n");
}
Client:
//TCP客户端
#pragma comment(lib,"WS2_32")
#include"winsock.h"
#include"stdio.h"
#include <windows.h>
声明IP头数据结构,ICMP协议是IP层的一个协议,但是由于差错报告在发送给报文源发方时可能也要经过若干子网,因此牵涉到路由选择等问题,所以ICMP报文需通过IP协议来发送。
//ICMP数据报的数据发送前需要两级封装:首先添加ICMP报头形成ICMP报文,再添加IP报头形成IP数据报
typedef struct _IPHeader // 20字节的IP头
{
UCHAR iphVerLen; // 版本号和头长度(各占4位)
UCHAR ipTOS; // 服务类型
USHORT ipLength; // 封包总长度,即整个IP报的长度
USHORT ipID; // 封包标识,惟一标识发送的每一个数据报
USHORT ipFlags; // 标志和片偏移
UCHAR ipTTL; // 生存时间,就是TTL,指出IP数据报能在网络上停留的最长时间,其值由发送方设定,并在经过路由的每一个节点时减一,当该值为0时,数据报将被丢弃
UCHAR ipProtocol; // 协议,可能是TCP、UDP、ICMP等
USHORT ipChecksum; // 校验和
ULONG ipSource; // 源IP地址
ULONG ipDestination; // 目标IP地址
} IPHeader, *PIPHeader;
//ICMP头数据结构
typedef struct icmp_hdr
{
unsigned char icmp_type; // 消息类型
unsigned char icmp_code; // 代码
unsigned short icmp_checksum; // 校验和
unsigned short icmp_id; // 用来惟一标识此请求的ID号,通常设置为进程ID
unsigned short icmp_sequence; // 序号
unsigned long icmp_timestamp; // 数据传输时间
}ICMP_HDR, *PICMP_HDR;
//ICMP回送请求的数据结构
typedef struct _EchoRequest
{
ICMP_HDR icmphdr;
char cData[32];
}ECHOREQUEST,*PECHOREQUEST;
//ICMP回送应答的数据结构
#define REQ_DATASIZE 32
typedef struct _EchoReply
{
IPHeader iphdr;
ECHOREQUEST echoRequest;
}ECHOREPLAY,*PECHOREPLAY;
// 校验和的计算
// 以16位的字为单位将缓冲区的内容相加,如果缓冲区长度为奇数,
// 则再加上一个字节。它们的和存入一个32位的双字中
//USHORT checksum(USHORT* buff, int size);
USHORT checksum(USHORT* buff, int size)
{ u_long cksum = 0;
while(size>1) // 将数据以字为单位累加到cksum 中
{
cksum=cksum+ *buff;
buff= buff +1;
size= size- sizeof(USHORT); //等价于size=size-2;
}
if(size==1) // 共有奇数个字节将最后一个字节扩展为字,再累加
{
USHORT u=0;
u=(USHORT)(*(UCHAR*)buff);
cksum = cksum +u;
}
// 校验位计算
//高16位和低16位相加
cksum = (cksum >> 16) + (cksum & 0x0000ffff);
cksum = cksum+(cksum >> 16);//本身再加上当前的高16位
u_short answer=(u_short)(~cksum);//取反并转换为16位数
return (answer);
}
void Sock();
int getmax(int backTime[],int n) // 计算最大时间
{
int nmax = backTime[0];
for(int i=0;i<n;i++)
{
if(nmax < backTime[i])
{
nmax = backTime[i];
}
}
return nmax;
}
int getmin(int backTime[],int n) // 计算最小时间
{
int nmax = backTime[0];
for(int i=0;i<n;i++)
{
if(nmax > backTime[i])
{
nmax = backTime[i];
}
}
return nmax;
}
int getavg(int backTime[],int n) // 计算平均值
{
int nmax = 0;
for(int i=0;i<n;i++)
{
nmax += backTime[i];
}
return nmax/n;
}
void ping(){
WSADATA wsaData;
WORD version = MAKEWORD(2, 2);
WSAStartup(version, &wsaData); //载入Winsock库
char DestIp[] = "0"; // 目的IP地址,即要Ping的IP地址
printf("请输入需要Ping的IP地址:");
gets(DestIp);
printf("\n正在创建套接字..............................\n");
SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
SOCKADDR_IN dest; // 设置目的地址
dest.sin_family = AF_INET;
dest.sin_port = htons(0); // 0表示程序执行时系统自动分配一个
dest.sin_addr.S_un.S_addr = inet_addr(DestIp);
ECHOREQUEST echoReq; // 创建ICMP封包(回送请求)
echoReq.icmphdr.icmp_type = 8;
echoReq.icmphdr.icmp_code = 0;
echoReq.icmphdr.icmp_id = (USHORT)GetCurrentProcessId();
echoReq.icmphdr.icmp_checksum = 0;
echoReq.icmphdr.icmp_sequence = 0;
// 填充数据部分,可以为任意
memset(&echoReq.cData, 'E', 32);//Sets buffers to a specified character.
// 开始发送和接收ICMP封包
USHORT nSeq = 0;
SOCKADDR_IN from;
struct timeval timeout;
timeout.tv_sec = 100000;
timeout.tv_usec = 0;
int nLen = sizeof(from);
int sendCount = 0; // 发送的数据包数
int backCount = 0;// 返回的数据包个数;
int backTime[4] = {0,0,0,0}; // 返回的数据包用的时间
int backTime_index = 0;// 数组游标
printf("\n正在Ping :%s\n",DestIp);
int nCount = 0;
while(TRUE){
//int nCount = 0;
int nRet;
if(nCount++ == 4) break;
echoReq.icmphdr.icmp_checksum = 0;
echoReq.icmphdr.icmp_timestamp = GetTickCount(); // GetTickCount() 系统开始后,已经经过的毫秒数
echoReq.icmphdr.icmp_sequence = nSeq++;
echoReq.icmphdr.icmp_checksum = checksum((USHORT*)&echoReq, sizeof(echoReq));
nRet = sendto(sRaw, (char*)&echoReq, sizeof(echoReq), 0,(SOCKADDR *)&dest, sizeof(dest));
if(nRet == SOCKET_ERROR){
printf(" sendto() failed: %d \n", WSAGetLastError());
return ;
}
else
{
sendCount++; // 发送的数据包加1,
}
ECHOREPLAY echoReply;//接收回送应答包
nRet = recvfrom(sRaw, (char*)&echoReply,sizeof(ECHOREPLAY), 0,(sockaddr*)&from, &nLen);
if (nRet == SOCKET_ERROR)
{
printf(" recvfrom() failed: %d\n", WSAGetLastError());
return ;
}
else
{
backCount++;
}
// 下面开始解析接收到的封包
if(nRet < sizeof(ECHOREPLAY)){
printf(" Too few bytes from %s \n", inet_ntoa(from.sin_addr));
}
// 接收到的数据中包含IP头,IP头大小为20个字节
if(echoReply.echoRequest.icmphdr.icmp_type != 0) { // 回显
printf(" nonecho type %d
recvd \n",echoReply.echoRequest.icmphdr.icmp_type);
return ;
}
if(echoReply.echoRequest.icmphdr.icmp_id!= GetCurrentProcessId())
{
printf(" someone else's packet! \n");
return ;
}
printf(" %d bytes Reply from %s:",
nRet,inet_ntoa(from.sin_addr));
printf(" icmp_seq = %d. ",echoReply.echoRequest.icmphdr.icmp_sequence);
int nTick = GetTickCount();
int time = nTick - echoReply.echoRequest.icmphdr.icmp_timestamp;
printf(" time: %d ms",time);
backTime[backTime_index] = time;
backTime_index++;
printf(" TTL= %d ", echoReply.iphdr.ipTTL);
printf(" \n");
Sleep(1000);
}
// 显示统计信息
printf("================Ping 的统计信息=================\n");
double ratio = (double)(sendCount-backCount)/(double)sendCount;
printf("\n数据包:\n已发送 = %d ,\n已接收 = %d ,\n丢失 = %d ( %.0f%% 丢失)\n",sendCount,backCount,sendCount-backCount,ratio*100);
printf("往返行程的估计时间:\n");
printf("\n最短 = %d ms,\n最长 = %d ms,\n平均 = %d ms\n",getmin(backTime,backCount),getmax(backTime,backCount),getavg(backTime,backCount));
closesocket(sRaw);
WSACleanup();//释放Winsock库
//建立服务器连接
}
void sock(){ //建立与客户端的连接
SOCKET sock;
WSADATA wsadata;
char buff[1000];
struct sockaddr_in sai;
WSAStartup(MAKEWORD(1,1),&wsadata);//加载套接字库和版本协商
sock=socket(AF_INET,SOCK_STREAM,0);
sai.sin_family = AF_INET;
sai.sin_port = htons(4777);
sai.sin_addr.s_addr = inet_addr("127.0.0.1");
connect(sock,(struct sockaddr*)&sai,sizeof(sai));
printf("=================接受数据========================\n\n\n");
while(true)
{
int i=1;
for(i=1;i<=5;i++) //建立一个for循环,接受5次数据
{
recv(sock,buff,1000,0);
printf("第%d个电脑的数据为%s\n\n",i,buff);
}
break;
}
closesocket(sock);
WSACleanup();
}
void main(){
printf("客户机程序(数据中心)\n\n\n\n");
for(int i=0;i<5;i++) //ping5次
{
ping();
}
printf("是否接受数据:"); //建立一个判断语句,使用户确定是否接受数据
int chose;
scanf("%d",&chose);
if(chose=1) //黑窗口输入1,接受数据
{
printf("=====================客户端启动========================\n");
sock();
}
}
程序运行
客户端先ping5次
平后,客户端确定,是否接受服务端的数据
确定接受后,客户端显示接受到的数据