Include the header file
网络编程在Windows平台上有俩个主要版本:Winsock1和Winsock2
#include <WinSock.h>
#pragma comment(lib, "WSock32.Lib")
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
//获取处理计算机硬件设备信息
#include <IPHlpApi.h>
#pragma comment(lib, "IPHLPAPI.lib")
//自定义的报文结构体
typedef struct INFO_SCAN_t{
unsigned short header;
unsigned short dev_number;
unsigned short dev_ver;
unsigned short expand_len;
}INFO_SCAN;
#define SCANPORT 6000 自定义端口号
Code:
WORD socketVersion = MAKEWORD(2,2);
WSADATA wsaData;
if(WSAStartup(socketVersion, &wsaData) == 0){
qDebug()<<"确认网络模块加载成功,可以进行网络通信";
}
WORD:typedef unsigned short
MAKEWORD (2,2 &): // MAKEWORD action is converted to the binary decimal number, then spliced together to form a bit: 0,000,001,000,000,010; Return value (1000000010) 514
struct WSADATA {// Windows Sockets data
WORD wVersion; // Windows sockets DLL version to be used; high byte storage sub-version number, the major version low byte storage; may return this value WORD MAKEWORD (BYTE, BYTE)
WORD wHighVersion; // This DLL can support Windows sockets highest standard version, basically the same as the wVersion
char szDescription [WSADESCRIPTION_LEN + 1]; // to ASCLL null-terminated string, DLL description will be copied to the Windows sockets achieve this string
char szSystemStatus [WSASYS_STATUS_LEN + 1]; // ... relating to the status or configuration information copied to the string
unsigned short iMaxSockets; // maximum number of single process can open the socket
unsigned short iMaxUdpDg; maximum User Datagram Protocol (UDP) is // applications can transmit or receive packet size (bytes), default 0;
char * lpVendorInfo; // manufacturer information (useless)
} wSAData
WSAStartup : loading the Winsock dynamic link library, the operating system that we use the library file, load the socket library, loaded successfully return 0
// Get the local IP address
char szText[256];
int iRet;
iRet = gethostname(szText, 256);
HOSTENT *host = gethostbyname(szText);
char *p = host->h_addr_list[0];
in_addr ip_addr;//
memcpy(&(ip_addr.S_un.S_addr), p, host->h_length);
string ip = ::inet_ntoa(ip_addr);//本地IP地址
qDebug()<<"local IP:"<<QString::fromStdString(ip);
int the gethostname ( char * name , int the namelen ); // get the local host name or domain name, the parameters are: variable storage host name, the size of the buffer
struct hostent gethostbyname ( const char * name ); // * name is the domain name or host name, the return value is hostent structure, error return NULL;
struct hostent {
char * h_name ; // host canonical name
char ** h_aliases ; // host alias (there may be multiple)
Short h_addrtype ; // host IP type (ipv4 (AF_INET), ipv6 ( AF_INET6))
Short h_length ; length // host IP address
char ** h_addr_list ; // host IP addresses to network storage preface, print need to call inet_ntop () / inet_ntoa ()
#define h_addr h_addr_list[0]//
};
Denotes a 32 -bit IPv4 address,
struct in_addr {
union { //255. 255. 255. 0
struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { USHORT s_w1,s_w2; } S_un_w;
ULONG s_addr ; // network byte order IP address stored
} S_un ;
// this unit IP-> mark address -> broadcast address
in_addr mask_addr;
string mask = GetMaskFromIp(ip);//获取该地址的子网掩码
mask_addr.S_un.S_addr = inet_addr(mask.c_str());//将string子网掩码地址,转成in_addr(将点分制IP:192.168.0.1转成结构体所需的32位二进制方式的IP(0xC0A80001))
ULONG domain_ul = ip_addr.S_un.S_addr & mask_addr.S_un.S_addr;
//网络顺序的IP广播地址:192.168.0.255
ULONG addr_ul = (~(mask_addr.S_un.S_addr)) | domain_ul;
//.分广播IP,测试用
in_addr m_ip;
m_ip.S_un.S_addr=addr_ul;
ip = ::inet_ntoa(m_ip);
qDebug()<<"m_local IP:"<<QString::fromStdString(ip);
string Widget::GetMaskFromIp(const string &ip)
{
string ret;
PIP_ADAPTER_INFO pAdapterInfo;
PIP_ADAPTER_INFO pAdapter = NULL;
ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO);
pAdapterInfo = (IP_ADAPTER_INFO *)malloc( sizeof(IP_ADAPTER_INFO) );
if( ERROR_BUFFER_OVERFLOW == GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) )
{
free(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *)malloc( ulOutBufLen );
}
if( NO_ERROR == GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) )
{
pAdapter = pAdapterInfo;
while(pAdapter)
{
if(ip == pAdapter->IpAddressList.IpAddress.String)
{
ret = pAdapter->IpAddressList.IpMask.String;
break;
}
pAdapter = pAdapter->Next;
}
}
if( pAdapterInfo )
{
free( pAdapterInfo );
}
return ret;
}
// set each other's IP, port
struct sockaddr_in sin;
sin.sin_family = AF_INET;//协议族IPv4
sin.sin_port = htons(SCANPORT);//htons将主机字节序转为网络字节序,端口号
sin.sin_addr.S_un.S_addr = addr_ul;//网络顺序的广播IP地址
struct sockaddr_in {
Short the sin_family ; // refer protocol family AF_INET
USHORT The sin_port ; // port number (Network Byte Order)
IN_ADDR sin_addr ; // store IP addresses, the data structure used in_addr
CHAR sin_zero for [ . 8 ]; // to make sockaddr and sockaddr_in two data structures remain the same size of the null bytes reserved
}
// Specify the local IP, port
struct sockaddr_in sinlocal;
sinlocal.sin_family = AF_INET;//协议族IPv4
sinlocal.sin_port = htons(SCANPORT);//htons将主机字节序转为网络字节序,端口号
sinlocal.sin_addr = (ip_addr);
// data to be sent to initialize
char sendData[128];
memset(sendData, 0x0, sizeof(sendData));//数组清空
INFO_SCAN info_scan;//报文头结构体赋值(发送的数据)
info_scan.header = 0xAA55;
info_scan.dev_number = 0x0001;
info_scan.dev_ver = 0x0001;
info_scan.expand_len = 0x0;
memcpy(sendData, &info_scan, sizeof(info_scan));
// send data out sendto
int sclient = socket(AF_INET, SOCK_DGRAM, 0);//SOCK_DGRAM指定为UDP
iRet = bind(sclient, (struct sockaddr*)&sinlocal, sizeof(struct sockaddr_in));//绑定本机信息
iRet = sendto(sclient, sendData, 128, 0, (sockaddr *)&sin, sizeof(sin));
// create a network capable of communicating socket
int socket(int domain,int type,int protocol);
domain protocol family: AF_UNIX (native communication), AF_INET ( the TCP / the IP - the IPv4 ), the AF_INET6 ( the TCP / the IP - the IPv6 )
type socket types: SOCK_STREAM ( TCP stream), SOCK_DGRAM ( UDP datagram), SOCK_RAM (raw socket)
Protocol : generally set 0 , the domain types of parameters are unknown, it may be determined protocol
// After creating a socket calls socket function, the bind function is responsible for connecting information socket to the local address and port
int bind(int sockfd,const struct sockaddr*my_addr,socklen_t addrlen);
sockfd : Returns the file descriptor after calling socket function (return value)
my_addr : pointing sockaddr pointer structure (the structure is stored in the port and IP address information)
addrlen : structure sockaddr length
// used to pass data from the other host specified socket (dedicated to the UDP )
int sendto(int s,const void*msg,int len,unsigned int flags,const struct sockaddr*to,int tolen);
S : connection built as socket, if using the UDP protocol does not require the connection operation,
MAG : For connection to the data content
the flags : generally located 0
to : used to specify the network address to be transferred
tolen : the sockaddr results length
// receiving part
struct sockaddr_in sin_recv;//定义接收时的协议,端口等
int sclient_recv = socket(AF_INET, SOCK_DGRAM, 0/*UDP*/);
sin_recv.sin_family = AF_INET;
sin_recv.sin_port = htons(SCANPORT+1);
sin_recv.sin_addr.s_addr = htonl(INADDR_ANY);//设置接收时来者不拒所有IP都收
// non-blocking mode
ULONG iMode = 1;
ioctlsocket(sclient_recv,FIONBIO,&iMode);
/ / Set the network nonblocking
int ioctlsocket(SOCKET s,long cmd,ulong*argp);
S : identifying a socket descriptor
cmd : for socket s operation command; the FIONBIO (enable or disable the socket s nonblocking mode), FIONREAD (determined socket s the amount of data is automatically read), The SIOCATMARK (the band is determined whether all data has been Read)
argp : pointing cmd pointer command brought parameter ( 0 controlled blocking mode, a control nonblocking)
// binding information receiving socket
iRet = bind(sclient_recv, (struct sockaddr*)&sin_recv, sizeof(struct sockaddr_in));
fd_set l_reads;//要接收的IP信息集合,最多64个
FD_ZERO(&l_reads);//将l_reads清空
FD_SET(sclient_recv, &l_reads);//将sclient加入l_reads集合
//控制等待时间
timeval l_timeout;
l_timeout.tv_sec = 5;
l_timeout.tv_usec = 0;
FD_ZERO (& the SET); // Clear
The FD_SET ( fd , & set); // set the set fd added
FD_CLR macros ( fd , & set); // set removed from the set of fd
FD_ISSET ( fd , & set); // tests whether fd collection set in
//Receive information
while(1){
//检查fd_set里的socket是否有信号到来
int l_nErr = select(sclient_recv+1, &l_reads, NULL, NULL, &l_timeout);
if(l_nErr<=0) break;
if(FD_ISSET(sclient_recv, &l_reads)){
// FD_ISSET判断fd_set里的具体ip,socket是哪个
struct sockaddr_in sin;//记录接收到远程数据的计算机的IP
int len = sizeof(sin);
char recvData[128];
memset(recvData,0,128);
//获取到的数据包解析出,数据,发送端IP
iRet = recvfrom(sclient_recv, recvData, 128, 0, (sockaddr *)&sin, &len); //0 flags MSG_DONTWAIT //操作不会被阻塞 MSG_WAITALL //要求阻塞操作 or
if(iRet==-1){
break;
}
//将接收到的数据解析给结构体
INFO_SCAN info_scan;
memset(&info_scan, 0x0, sizeof(info_scan));
memcpy(&info_scan, recvData, sizeof(info_scan));
if(info_scan.header == 0x55AA && info_scan.dev_number == 0x0001 && info_scan.dev_ver == 0x0001){
in_addr m_ip;
m_ip=sin.sin_addr;
ip = ::inet_ntoa(m_ip);
qDebug()<<"receive data success"<<QString::fromStdString(ip);
QString str=QString::fromStdString(ip);
}
}
}
qDebug()<<"success";
// test specified fd readable? Write? Abnormal condition to be treated? Analyzing the information set in the socket there is received
int select(int nfds,fd_set*readset,fd_set*writeset,fd_set*exceptset,struct timeval*timeout);
NFDs : File Description digits to be checked (checked fd_set of several)
readset : for checking the readability of a character set of file description
writeset : a set of files used to check writability descriptor
exceptset : used to check whether an abnormal condition has occurred in the file descriptor (not included in the error exception condition)
timeout : NULL (block until a fd bit is set to 1 the function does not return)
timeout structure pointed to by a non-zero time, waiting for a fixed time, there is a fd bit is set to 1 or the time runs out, functions return
timeout pointed configuration, time set to 0 (non-blocking: End Function Check each fd returns immediately after)
Return Value: returns the corresponding bit of throw 1 of fd total