Windows Network Communication

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

Published 104 original articles · won praise 22 · views 40000 +

Guess you like

Origin blog.csdn.net/qq_41672557/article/details/103303024