IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 计网 | C语言Socket编程获取本机IP及指定域名IP -> 正文阅读

[网络协议]计网 | C语言Socket编程获取本机IP及指定域名IP

实验目的和要求

  • 使用Winsock提供的API函数 ,利用Socket获得本机IP和本机名称。
  • 使用Winsock提供的API函数 ,利用Socket获得百度域名的IP 。

结果预览

程序最终效果图

环境记录

名称
操作系统Windows 11 家庭中文版22H2
内存16GB
CPUIntel? Core? i7-8750H CPU @ 2.20GHz 2.20 GHz
IDEDEV-C++ 5.10

目录

实验记录

配置IDE

需要注意的是引用winsock2.h头文件后,还需要链接该头文件的实现文件,在本机上使用宏#pragma comment (lib, “ws2_32.lib”)无法成功添加该实现文件ws2_32。手动编译时会出现如下报错信息:

DEV-C++下编译出错
参考网上许多解决办法没有效果,最后解决办法如下:
[info]如下图,可以打开DEV-C++菜单栏的Toos->Compiler Options-> General,找到Add the following commands when calling the compiler:勾上复选框,在下面的输入框中写入-lwsock32并确定。这样编译运行的时候就可以自动链接了。[/info]

这样做相当于编译命令变成了gcc socket_exp.c -o socket_exp.exe -lwsock32 ,其中socket_exp是我的文件名。举一反三,在VSCode中就可以自己手动链接了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X0WScxDB-1652950414518)(https://s3.bmp.ovh/imgs/2022/04/23/fc82e28557d20dda.png)]

新建程序

使用IDE新建一个C语言程序进行编写。代码如下:

#include <stdio.h>
#include <winsock2.h>

void queryLocalIP() {
	WSADATA data;
	if(WSAStartup(MAKEWORD(1,1),&data)!=0){
		printf("初始化错误");
    }
    
  	char host[255]="";
	if(gethostname(host,sizeof(host))==SOCKET_ERROR){
		printf("无法获取计算机主机名\n");
	}
	else{
		printf("本机名称为:%s\n",host);
	}

	struct hostent *p=gethostbyname(host);
	if(p==0){
		printf("无法获取计算机主机名及IP\n");
	}
	else{
		
		//本机IP:循环输出本机所有网卡的IP,其中包括虚拟网卡 
    	int i;
    	for(i=0;p->h_addr_list[i]!=0;i++){
    		struct in_addr in;
    		memcpy(&in,p->h_addr_list[i],sizeof(struct in_addr));
    		printf("本机的第%d块网卡的IP为:%s\n",i+1,inet_ntoa(in));
    		//cout<<"第"<<i+1<<"块网卡的IP为:"<<inet_ntoa(in)<<endl;
    	}
	}
	WSACleanup();
} 

void queryHostNameIP(char *host) {
	WSADATA data;
	if(WSAStartup(MAKEWORD(1,1),&data)!=0){
		printf("初始化错误");
    }
  
	//char host[255];

	struct hostent *p=gethostbyname(host);
	if(p==0){
		printf("无法获取%s的信息\n",host);
	}
	else{
		//本机IP:循环输出本机所有网卡的IP,其中包括虚拟网卡 
    	int i;
    	for(i=0;p->h_addr_list[i]!=0;i++){
    		struct in_addr in;
    		memcpy(&in,p->h_addr_list[i],sizeof(struct in_addr));
    		printf("解析%s的第%d个IP为:%s\n",host,i+1,inet_ntoa(in));
    		//cout<<"第"<<i+1<<"块网卡的IP为:"<<inet_ntoa(in)<<endl;
    	}
	}
	
	WSACleanup();
}
 
int main(){
	queryLocalIP();
	
	printf("=================================\n");
	char*  hostname = "www.baidu.com";
	queryHostNameIP(hostname); 
	printf("=================================\n");
	//输出个人信息
	printf("Ranly 2022/4/23");
	return 0;
}

ok,下面编译运行就正常了。用完以后记得把编译设置里加上去的参数去掉,以便以后写其他代码出问题。

实验分析

winsock2常见结构体和方法

gethostname获取本机主机名

int gethostname(char *name, size_t len);

参数说明:

参数类型说明
namechar *用于存储获得的主机名,其长度必须为len字节或是更长。
lensize_t接收缓冲区的最大长度,可通过sizeof(name)获取。

返回值:

  • 如果函数成功,则返回0。
  • 如果发生错误则返回-1。错误号存放在外部变量errno中。

gethostbyname获取主机名对应信息

struct hostent *gethostbyname(const char *hostname);
参数说明:

参数类型说明
hostnameconst char *要查询的主机名,域名

返回值:

  • 如果函数失败,则返回0。
  • 如果成功,返回的指针指向的结构体中包含所需信息,具体如下小节所示。

hostent

对于一个hostname,可以通过gethostbyname(char *hostname);方法来获得一个hostent的结构体的指针。

传入的hostname可以是通过gethostname获取的本机主机名或是本地局域网内可被发现的其它主机的名字,例如 LBW's PC ,也可以是一个常见的网络域名,例如某度的二级域名 www.baidu.com

struct hostent {
    char *h_name; /* 主机的官方域名 */
   char **h_aliases; /* 一个以NULL结尾的主机别名数组 */
   int h_addrtype; /* 返回的地址类型,在Internet环境下为AF-INET */
   int h_length; /* 地址的字节长度 */
   char **h_addr_list; /* 一个以0结尾的二维数组,包含该主机的所有地址*/
};

详细解析:

  • h_name:官方域名(Official domain name)。官方域名代表某一主页,但实际上一些著名公司的域名并未用官方域名注册。
  • h_aliases:别名,可以通过多个域名访问同一主机。同一 IP 地址可以绑定多个域名,因此除了当前域名还可以指定其他域名。
  • h_addrtype:gethostbyname() 不仅支持 IPv4,还支持 IPv6,可以通过此成员获取IP地址的地址族(地址类型)信息,IPv4 对应 AF_INET,IPv6 对应 AF_INET6。
  • h_length:保存IP地址长度。IPv4 的长度为 4 个字节,IPv6 的长度为 16 个字节。
  • h_addr_list:这是最重要的成员。通过该成员以整数形式保存域名对应的 IP 地址。对于用户较多的服务器,可能会分配多个 IP 地址给同一域名,利用多个服务器进行均衡负载

sockaddr_in

struct sockaddr_in {
	short int sin_family;         /* 协议族 */
	unsigned short int sin_port;  /* 端口号 */
	struct in_addr sin_addr;      /* Internet 地址 */
	unsigned char sin_zero[8];    /* 和结构体 sockaddr 大小相同 */
};

in_addr

这个结构体就是32位的IP地址了。要进行格式化输出字符串,不要直接读取,而是使用char *inet_ntoa (struct in_addr);方法将in_addr类型的变量转换为char数组,从而可以pirntf为用.间隔的IP地址字符串。

struct in_addr {
	union {
	struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
	struct { u_short s_w1,s_w2; } S_un_w;
	u_long S_addr;
} S_un;

参考资料

https://blog.csdn.net/k916631305/article/details/109498205
https://blog.csdn.net/u011608357/article/details/18862853
https://baike.baidu.com/item/inet_ntoa%28%29/10082005
https://www.cnblogs.com/kex1n/p/5524644.html
http://c.biancheng.net/view/2357.html

博客首发:https://ranlychan.top/archives/476.html

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-05-21 19:17:01  更:2022-05-21 19:17:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 1:34:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码