有没有办法知道局域网哪台机子是服务器。
如何判断本地是否与服务器连接。
开机后没有与服务器连接上,后来连上了应该怎样获得连接的信息。
由于编写的软件是运行在客户端的,服务器端什么都没有,只是被动的接受消息。如果用PING来判断是否连通,应该怎么写,请教达人。最好能有个例子或代码,谢谢!急用,今天就要搞定
如何判断本地是否与服务器连接。
开机后没有与服务器连接上,后来连上了应该怎样获得连接的信息。
由于编写的软件是运行在客户端的,服务器端什么都没有,只是被动的接受消息。如果用PING来判断是否连通,应该怎么写,请教达人。最好能有个例子或代码,谢谢!急用,今天就要搞定
static int toflag;static int sock;
static char sendbuf[1500],recvbuf[1500];
static int datalen=56;
static int nsend=0;
static pid_t pid;
static char *host,namebuf[50];
static struct sockaddr_in to;
static struct sockaddr_in from;extern CLog g_log;void err_quit(char *msg)
{
//perror(msg);
printf("%s\n", msg);
//exit(1);
}unsigned short in_cksum(unsigned short *addr,int len)
{
int nleft=len;
int sum=0;
unsigned short *w=addr;
unsigned short answer=0;
while(nleft>1)
{
sum+=*w++;
nleft-=2;
}
if(nleft==1)
{
*(unsigned char *)(&answer)=*(unsigned char *)w;
sum+=answer;
}
sum=(sum>>16)+(sum&0xffff);
sum+=(sum>>16);
answer=~sum;
return(answer);
}void pinger(void)
{
struct icmp *icp;
int cc;
int i;
bzero(sendbuf,1500);
icp=(struct icmp *)sendbuf;
icp->icmp_type=ICMP_ECHO;
icp->icmp_code=0;
icp->icmp_seq=nsend++;
icp->icmp_id=pid;
gettimeofday((struct timeval *)icp->icmp_data,NULL);
cc=datalen+8;
icp->icmp_cksum=in_cksum((unsigned short *)icp,cc);
i=sendto(sock,sendbuf,cc,0,
(struct sockaddr *)&to,sizeof(struct sockaddr));
if(i<0||i!=cc)
err_quit("sendto error");
} int proc_pack(ssize_t len,struct timeval *tvrecv)
{
int hlen1,icmplen;
double rtt;
struct ip *ip;
struct icmp *icmp;
struct timeval *tvsend;
char buf[50];
ip=(struct ip *)recvbuf;
hlen1=ip->ip_hl<<2;
icmp=(struct icmp *)(recvbuf+hlen1);
if((icmplen=len-hlen1)<8)
{
err_quit("icmplen1");
return -1;
}
if(icmp->icmp_type==ICMP_ECHOREPLY)
{
if(icmp->icmp_id!=pid)
return -1;
if(icmplen<16)
return -1; return 0;
}
return -1;
}void sig_alrm(int signo)
{
signal(SIGALRM,sig_alrm);
pinger();
alarm(TIMEOUT);
//return;
}static void _alarmproc(int sig_num)
{
signal(SIGALRM, _alarmproc);
toflag = 1;
}int ping_loop(void)
{
int size;
int i;
int len;
ssize_t n;
fd_set rset, wset;
struct timeval tv;
int timeout = 1;
int bread; size = 60 * 1024;
if((sock=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP))<0)
{
//err_quit("create raw socket erro\n");
return -1;
} setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
FD_ZERO(&rset);
FD_SET(sock, &rset);
wset = rset;
tv.tv_sec = TIMEOUT;
tv.tv_usec = 0;
if(select(sock + 1, &rset, &wset, NULL, &tv) == 0)
{
//printf("in select()...\n");
} for(i = 0; i < 3; i++)
{
len=sizeof(from);
pinger();
if(errno==ETIMEDOUT)
{
//printf("pinger time out...\n");
g_log.printlog(93001);
return -1;
} n=recvfrom(sock,recvbuf,1500,0,(struct sockaddr *)&from,&len); if(n<0)
{
if(errno==EINTR)
return -1;
//continue;
else
return -1;
//err_quit("recvfrom");
}
gettimeofday(&tv,NULL);
if(proc_pack(n,&tv) == 0)
return 0;
}
return -1;
}int gsnping(char *hostip)
{
struct sigaction act;
struct hostent *ht;
int ret;
pid=getpid();
act.sa_handler=sig_alrm;
act.sa_flags=0; signal(SIGALRM,sig_alrm);
to.sin_family=AF_INET;
to.sin_addr.s_addr=inet_addr(hostip);
if(to.sin_addr.s_addr!=(unsigned int)-1)
host=hostip;
else
{
if(!(ht=gethostbyname(hostip)))
err_quit("gethostbyname");
to.sin_family=ht->h_addrtype;
memmove(&to.sin_addr,ht->h_addr,ht->h_length);
strncpy(namebuf,ht->h_name,sizeof(namebuf)-1);
host=namebuf;
} ret = ping_loop(); close(sock);
return ret;
}
// ping.cpp文件#include "../common/initsock.h"
#include "../common/protoinfo.h"
#include "../common/comm.h"#include <stdio.h>
CInitSock theSock;
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;
int main()
{
// 目的IP地址,即要Ping的IP地址
char szDestIp[] = "10.16.115.178"; // 127.0.0.1 // 创建原始套节字
SOCKET sRaw = ::socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); // 设置接收超时
SetTimeout(sRaw, 1000, TRUE); // 设置目的地址
SOCKADDR_IN dest;
dest.sin_family = AF_INET;
dest.sin_port = htons(0);
dest.sin_addr.S_un.S_addr = inet_addr(szDestIp); // 创建ICMP封包
char buff[sizeof(ICMP_HDR) + 32];
ICMP_HDR* pIcmp = (ICMP_HDR*)buff;
// 填写ICMP封包数据
pIcmp->icmp_type = 8; // 请求一个ICMP回显
pIcmp->icmp_code = 0;
pIcmp->icmp_id = (USHORT)::GetCurrentProcessId();
pIcmp->icmp_checksum = 0;
pIcmp->icmp_sequence = 0;
// 填充数据部分,可以为任意
memset(&buff[sizeof(ICMP_HDR)], 'E', 32);
// 开始发送和接收ICMP封包
USHORT nSeq = 0;
char recvBuf[1024];
SOCKADDR_IN from;
int nLen = sizeof(from);
while(TRUE)
{
static int nCount = 0;
int nRet;
if(nCount++ == 4)
break;
pIcmp->icmp_checksum = 0;
pIcmp->icmp_timestamp = ::GetTickCount();
pIcmp->icmp_sequence = nSeq++;
pIcmp->icmp_checksum = checksum((USHORT*)buff, sizeof(ICMP_HDR) + 32);
nRet = ::sendto(sRaw, buff, sizeof(ICMP_HDR) + 32, 0, (SOCKADDR *)&dest, sizeof(dest));
if(nRet == SOCKET_ERROR)
{
printf(" sendto() failed: %d \n", ::WSAGetLastError());
return -1;
}
nRet = ::recvfrom(sRaw, recvBuf, 1024, 0, (sockaddr*)&from, &nLen);
if(nRet == SOCKET_ERROR)
{
if(::WSAGetLastError() == WSAETIMEDOUT)
{
printf(" timed out\n");
continue;
}
printf(" recvfrom() failed: %d\n", ::WSAGetLastError());
return -1;
} // 下面开始解析接收到的ICMP封包
int nTick = ::GetTickCount();
if(nRet < sizeof(IPHeader) + sizeof(ICMP_HDR))
{
printf(" Too few bytes from %s \n", ::inet_ntoa(from.sin_addr));
}
// 接收到的数据中包含IP头,IP头大小为20个字节,所以加20得到ICMP头
ICMP_HDR* pRecvIcmp = (ICMP_HDR*)(recvBuf + 20); // (ICMP_HDR*)(recvBuf + sizeof(IPHeader));
if(pRecvIcmp->icmp_type != 0) // 回显
{
printf(" nonecho type %d recvd \n", pRecvIcmp->icmp_type);
return -1;
} if(pRecvIcmp->icmp_id != ::GetCurrentProcessId())
{
printf(" someone else's packet! \n");
return -1;
}
printf(" %d bytes from %s:", nRet, inet_ntoa(from.sin_addr));
printf(" icmp_seq = %d. ", pRecvIcmp->icmp_sequence);
printf(" time: %d ms", nTick - pRecvIcmp->icmp_timestamp);
printf(" \n"); ::Sleep(1000);
} return 0;
}
// comm.h文件// 包含一些公共函数#ifndef __COMM_H__
#define __COMM_H__
// 校验和的计算
// 以16位的字为单位将缓冲区的内容相加,如果缓冲区长度为奇数,
// 则再加上一个字节。它们的和存入一个32位的双字中
USHORT checksum(USHORT* buff, int size);BOOL SetTTL(SOCKET s, int nValue);
BOOL SetTimeout(SOCKET s, int nTime, BOOL bRecv = TRUE);
#endif // __COMM_H__//////////////////////////////////////////////////
// comm.cpp文件
#include <winsock2.h>
#include <windows.h>
#include "Ws2tcpip.h"#include "comm.h"
USHORT checksum(USHORT* buff, int size)
{
unsigned long cksum = 0;
while(size>1)
{
cksum += *buff++;
size -= sizeof(USHORT);
}
// 是奇数
if(size)
{
cksum += *(UCHAR*)buff;
}
// 将32位的chsum高16位和低16位相加,然后取反
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >> 16);
return (USHORT)(~cksum);
}BOOL SetTTL(SOCKET s, int nValue)
{
int ret = ::setsockopt(s, IPPROTO_IP, IP_TTL, (char*)&nValue, sizeof(nValue));
return ret != SOCKET_ERROR;
}BOOL SetTimeout(SOCKET s, int nTime, BOOL bRecv)
{
int ret = ::setsockopt(s, SOL_SOCKET,
bRecv ? SO_RCVTIMEO : SO_SNDTIMEO, (char*)&nTime, sizeof(nTime));
return ret != SOCKET_ERROR;
}
// initsock.h文件#include <winsock2.h>
#pragma comment(lib, "WS2_32") // 链接到WS2_32.libclass 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();
}
};
//////////////////////////////////////////////////
// protoinfo.h文件/*定义协议格式
定义协议中使用的宏 */
#ifndef __PROTOINFO_H__
#define __PROTOINFO_H__
#define ETHERTYPE_IP 0x0800
#define ETHERTYPE_ARP 0x0806typedef struct _ETHeader // 14字节的以太头
{
UCHAR dhost[6]; // 目的MAC地址destination mac address
UCHAR shost[6]; // 源MAC地址source mac address
USHORT type; // 下层协议类型,如IP(ETHERTYPE_IP)、ARP(ETHERTYPE_ARP)等
} ETHeader, *PETHeader;
#define ARPHRD_ETHER 1// ARP协议opcodes
#define ARPOP_REQUEST 1 // ARP 请求
#define ARPOP_REPLY 2 // ARP 响应
typedef struct _ARPHeader // 28字节的ARP头
{
USHORT hrd; // 硬件地址空间,以太网中为ARPHRD_ETHER
USHORT eth_type; // 以太网类型,ETHERTYPE_IP ??
UCHAR maclen; // MAC地址的长度,为6
UCHAR iplen; // IP地址的长度,为4
USHORT opcode; // 操作代码,ARPOP_REQUEST为请求,ARPOP_REPLY为响应
UCHAR smac[6]; // 源MAC地址
UCHAR saddr[4]; // 源IP地址
UCHAR dmac[6]; // 目的MAC地址
UCHAR daddr[4]; // 目的IP地址
} ARPHeader, *PARPHeader;
// 协议
#define PROTO_ICMP 1
#define PROTO_IGMP 2
#define PROTO_TCP 6
#define PROTO_UDP 17typedef struct _IPHeader // 20字节的IP头
{
UCHAR iphVerLen; // 版本号和头长度(各占4位)
UCHAR ipTOS; // 服务类型
USHORT ipLength; // 封包总长度,即整个IP报的长度
USHORT ipID; // 封包标识,惟一标识发送的每一个数据报
USHORT ipFlags; // 标志
UCHAR ipTTL; // 生存时间,就是TTL
UCHAR ipProtocol; // 协议,可能是TCP、UDP、ICMP等
USHORT ipChecksum; // 校验和
ULONG ipSource; // 源IP地址
ULONG ipDestination; // 目标IP地址
} IPHeader, *PIPHeader;
// 定义TCP标志
#define TCP_FIN 0x01
#define TCP_SYN 0x02
#define TCP_RST 0x04
#define TCP_PSH 0x08
#define TCP_ACK 0x10
#define TCP_URG 0x20
#define TCP_ACE 0x40
#define TCP_CWR 0x80typedef struct _TCPHeader // 20字节的TCP头
{
USHORT sourcePort; // 16位源端口号
USHORT destinationPort; // 16位目的端口号
ULONG sequenceNumber; // 32位序列号
ULONG acknowledgeNumber; // 32位确认号
UCHAR dataoffset; // 高4位表示数据偏移
UCHAR flags; // 6位标志位
//FIN - 0x01
//SYN - 0x02
//RST - 0x04
//PUSH- 0x08
//ACK- 0x10
//URG- 0x20
//ACE- 0x40
//CWR- 0x80 USHORT windows; // 16位窗口大小
USHORT checksum; // 16位校验和
USHORT urgentPointer; // 16位紧急数据偏移量
} TCPHeader, *PTCPHeader;typedef struct _UDPHeader
{
USHORT sourcePort; // 源端口号
USHORT destinationPort;// 目的端口号
USHORT len; // 封包长度
USHORT checksum; // 校验和
} UDPHeader, *PUDPHeader;#endif // __PROTOINFO_H__