包含头文件

网络编程在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  自定义端口号

代码:

WORD socketVersion = MAKEWORD(2,2);WSADATA wsaData;if(WSAStartup(socketVersion, &wsaData) == 0){qDebug()<<"确认网络模块加载成功,可以进行网络通信";}

WORD:typedef unsigned short

MAKEWORD(2,2)://MAKEWORD的作用是将十进制数转成2进制,再按位拼接到一起形成:00000010  00000010;返回值(10  00000010)514

struct WSAData {//Windows Sockets数据

WORD  wVersion;//Windows sockets DLL将使用的版本;高位字节存储副版本号,低位字节存储主版本号;可以用WORD MAKEWORD(BYTE,BYTE)返回这个值

WORD  wHighVersion;//这个DLL能够支持的Windows sockets规范的最高版本,基本与wVersion相同

char  szDescription[WSADESCRIPTION_LEN+1];//以null结尾的ASCLL字符串,DLL将Windows sockets实现的描述拷贝到这个字符串

char  szSystemStatus[WSASYS_STATUS_LEN+1];//...把有关的状态或配置信息拷贝到该字符串

unsigned short iMaxSockets;//单个进程能够打开的socket的最大数目

unsigned short iMaxUdpDg;//应用程序能够发送或接收的最大的用户数据包协议(UDP)的数据包大小(字节),默认0;

char*          lpVendorInfo;//制造商信息(没用)

} WSADATA

WSAStartup:载入合适的Winsock动态链接库,向操作系统说明我们要用那个库文件,加载套接字库,返回0加载成功

//获取本地IP地址

    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 gethostname(char*name,int namelen); //得到本机主机名或域名,参数是:来存放主机名的变量,缓冲区的大小

struct hostent  gethostbyname( const char  * name); //*name是域名或主机名,返回值是hostent结构,错误返回NULL;

struct  hostent {

char  * h_name;//主机规范名

char  ** h_aliases;//主机别名(可以有多个)

short h_addrtype;//主机IP类型(ipv4(AF_INET),ipv6(AF_INET6))

short h_length;//主机IP地址的长度

char  **h_addr_list;//主机IP地址,以网络自序存储的,打印需要调用inet_ntop()/inet_ntoa()

#define h_addr    h_addr_list[0]//

};

表示一个32位的IPv4地址,

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;//按照网络字节顺序存储的IP地址

} S_un;

//通过本机IP->mark地址->广播地址

    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.255ULONG 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;
}

//设置对方的IP,端口

    struct sockaddr_in sin;sin.sin_family = AF_INET;//协议族IPv4sin.sin_port = htons(SCANPORT);//htons将主机字节序转为网络字节序,端口号sin.sin_addr.S_un.S_addr = addr_ul;//网络顺序的广播IP地址

struct sockaddr_in {

short   sin_family;//指代协议族 AF_INET

USHORT sin_port;//端口号(网络字节序)

IN_ADDR sin_addr;//存储IP地址,使用in_addr数据结构

CHAR sin_zero[8];//为了让sockaddr和sockaddr_in俩个数据结构保持大小相同而保留的空字节

}

//指定本机IP,端口

    struct sockaddr_in sinlocal;sinlocal.sin_family = AF_INET;//协议族IPv4sinlocal.sin_port = htons(SCANPORT);//htons将主机字节序转为网络字节序,端口号sinlocal.sin_addr = (ip_addr);

//要发送的数据进行初始化

  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));

//将数据发送出去sendto

    int sclient = socket(AF_INET, SOCK_DGRAM, 0);//SOCK_DGRAM指定为UDPiRet = bind(sclient, (struct sockaddr*)&sinlocal, sizeof(struct sockaddr_in));//绑定本机信息iRet = sendto(sclient, sendData, 128, 0, (sockaddr *)&sin, sizeof(sin));

// 创建一个能够进行网络通信的套接字

int socket(int domain,int type,int protocol);

domain协议族:AF_UNIX(本机通信)、AF_INET(TCP/IP-IPv4)、AF_INET6(TCP/IP-IPv6)

type套接字类型:SOCK_STREAM(TCP流)、SOCK_DGRAM(UDP数据报)、SOCK_RAM(原始套接字)

protocol:一般设为0,在domain参数未知的情况下,可以确定协议的种类

// 调用socket函数创建套接字后,bind函数负责将套接字与本机地址和端口等信息相连

int bind(int sockfd,const struct sockaddr*my_addr,socklen_t addrlen);

sockfd:调用socket函数后返回的文件描述符(返回值)

my_addr:指向sockaddr结构体的指针(该结构体中保存有端口和IP地址信息)

addrlen:结构体sockaddr的长度

//用来将数据由指定的socket传给对方主机(专用于UDP)

int sendto(int s,const void*msg,int len,unsigned int flags,const struct sockaddr*to,int tolen);

s:为已建好连线的socket,如果利用UDP协议则不需要经过连线操作,

mag:指向欲连线的数据内容

flags:一般设0

to:用来指定欲传送的网络地址

tolen:sockaddr的结果长度

//接收部分

  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都收

//非阻塞模式

     ULONG iMode = 1;ioctlsocket(sclient_recv,FIONBIO,&iMode);

//将网络设置为非阻塞模式

int ioctlsocket(SOCKET s,long cmd,ulong*argp);

s:一个标识套接口的描述字

cmd:对套接口s的操作命令;FIONBIO(允许或禁止套接口s的非阻塞模式)、FIONREAD(确定套接口s自动读入的数据量)、SIOCATMARK(确定是否所有的带外数据都已被读入)

argp:指向cmd命令所带参数的指针(0控制为阻塞方式,1控制为非阻塞方式)

//绑定接收套接字的信息

    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(&set);//清空

FD_SET(fd,&set);//将fd加入set集合

FD_CLR(fd,&set);//将fd从set集合中清除

FD_ISSET(fd,&set);//测试fd是否在set集合中

//接收信息

   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;//记录接收到远程数据的计算机的IPint len = sizeof(sin);char recvData[128];memset(recvData,0,128);//获取到的数据包解析出,数据,发送端IPiRet = recvfrom(sclient_recv, recvData, 128, 0, (sockaddr *)&sin, &len); //0 flags MSG_DONTWAIT  //操作不会被阻塞    MSG_WAITALL //要求阻塞操作   orif(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";

// 测试指定的fd可读?可写?有异常条件待处理?判断有没有set中的socket信息接收到

int select(int nfds,fd_set*readset,fd_set*writeset,fd_set*exceptset,struct timeval*timeout);

nfds:需要检查的文件描述字个数(检查到fd_set的第几位)

readset:用来检查可读性的一组文件描述字

writeset:用来检查可写性的一组文件描述字

exceptset:用来检查是否有异常条件出现的文件描述字(错误不包括在异常条件内)

timeout:NULL(阻塞,直到有一个fd位被置为1函数才返回)

timeout所指向的结构设为非零时间,等待固定时间,有一个fd位被置为1或者时间耗尽,函数均返回

timeout所指向的结构,时间设为0(非阻塞:函数检查完每个fd后立即返回)

返回值:返回对应位扔为1的fd的总数

Windows网络通信相关推荐

  1. Windows 网络通信编程

    前言 Wiindows网络编程并不需要太多知识,只要你会C语言就能够轻松学会.在这里我将介绍如何在Windows系统中进行网络通信,并附上一个完整的简单的网络通信代码. 目录 Socket套接字 简单 ...

  2. Windows网络通信(二):socket异步编程

    简述 这里使用的API和同步编程的API是差不多的,只多了一个ioctlsocket和select函数.这里面涉及一个很重要的结构体fd_set.这里用到的API大部分都是windows和linux通 ...

  3. Windows 网络通信套接字技术

    文章目录 一.TCP/IP介绍 1.TCP/IP体系结构 2.TCP/IP特点 3.TCP/IP协议与WinSock网络编程接口的关系 二.套接字原理 1.客户机/服务器模式 服务器端: 客户端: 2 ...

  4. Windows网络通信流量和网速监控设计(一)

    第二篇文章连接 文章目录 三种数据通信传输模式 一.单工通信 二.半双工通信 三.全双工通信 相关基础知识 1.__stdcall 2.GetIfTable()函数 3.MIB_IFTABLE结构体 ...

  5. VC网络编程-Winsock开发网络通信程序的经典入门

    Winsock开发网络通信程序的经典入门 对于许多初学者来说,网络通信程序的开发,普遍的一个现象就是觉得难以入手.许多概念,诸如:同步(Sync) / 异步(Async),阻塞(Block) / 非阻 ...

  6. TeamTalk源码分析之win-client

    windows的程序的基本原理: windows消息机制(消息如何产生.如何发送.如何处理,常见的消息有哪些.消息的优先级.如何自定义消息.窗体消息.常用控件消息) gdi原理(要熟悉gdi的各种对象 ...

  7. connect 连接超时

    原文地址:http://blog.csdn.net/codeheng/article/details/44625495 在使用TCP的connect连接服务器时,在默认情况下系统使用的是阻塞式sock ...

  8. TeamTalk源码分析(十一) —— pc客户端源码分析

           --写在前面的话  在要不要写这篇文章的纠结中挣扎了好久,就我个人而已,我接触windows编程,已经六七个年头了,尤其是在我读研的三年内,基本心思都是花在学习和研究windows程序上 ...

  9. 杨振宁:通过我的求学及研究经历,获得了这些启发与感受

    文章 | 杨振宁 来源 | <物理>第41卷第1期第1页,转自募格课堂 1933年到1937年我在北平崇德中学念了四年书,第一次接触到二十世纪的物理学就是在中学那间很小的图书馆看到了Jea ...

最新文章

  1. 四连通,和八连通的详解(MATLAB)
  2. 大学实习就要来了,买个性价比高的笔记本应付一下
  3. 一杯茶的时间,上手Zabbix
  4. Ensemble Methods——python
  5. 模版设计模式概述和使用
  6. android8 老手机,华为多款老旧手机获升安卓8.0,流畅度飙升!
  7. 成为Google认证机器学习工程师,零基础只需要2步?
  8. linux ntp 追赶,Linux 时间同步 ntpd
  9. BSD:Berkeley Software Distribution,伯克利软件套件
  10. 3534 helpmsg mysql net_MySQL出现NET HELPMSG 3534
  11. 约瑟夫环-单向循环链表
  12. ZooKeeper实际应用案例-开发实战
  13. pdf阅读神器推荐——PDF-XChange Editor V8
  14. 为什么要学计算机演讲稿,我们为什么要学习科学演讲稿
  15. spring源码:九大后置处理器
  16. MySQL下执行*.sql文件
  17. MATLAB数据预处理——导入,插补,绘图
  18. 中心性(centrality)
  19. JAVA建行银企直连报文加解密
  20. 【工具推荐】图形化Git客户端Sourcetree推荐

热门文章

  1. EMC设计攻略(4)——PCB设计
  2. SAP中BOM事务清单CS13中的物料数量单位逻辑梳理及格式调整处理实例
  3. python循环语句画图_Python基础之循环语句用法示例【for、while循环】
  4. Python GUI案例之看图猜成语开发(第二篇)
  5. 习题4.5 在键盘上输入数n,编程计算sum=1-1/2!+1/3!-...(-1)n-1(1/n!)。
  6. [SDM660 Android9.0]编译问题
  7. CF-ViT论文粗读
  8. 中国象棋,马不重复的走完每一格
  9. 《御龙天剑传》隐私政策
  10. 只有程序员才懂的10张幽默动图