- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在阅读 Beej 的“Guide to network programming”。
在他的一个介绍示例中,他谈到获取主机名的 IP 地址(例如 google.com 或 yahoo.com)。这是代码。
/*
** showip.c -- show IP addresses for a host given on the command line
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
struct addrinfo hints, *res, *p;
int status;
char ipstr[INET6_ADDRSTRLEN];
if (argc != 2) {
fprintf(stderr,"usage: showip hostname\n");
return 1;
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
hints.ai_socktype = SOCK_STREAM;
if ((status = getaddrinfo(argv[1], NULL, &hints, &res)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
return 2;
}
printf("IP addresses for %s:\n\n", argv[1]);
for(p = res; p != NULL; p = p->ai_next) {
void *addr;
char *ipver;
// get the pointer to the address itself,
// different fields in IPv4 and IPv6:
if (p->ai_family == AF_INET) { // IPv4
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
addr = &(ipv4->sin_addr);
ipver = "IPv4";
} else { // IPv6
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
addr = &(ipv6->sin6_addr);
ipver = "IPv6";
}
// convert the IP to a string and print it:
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
printf(" %s: %s\n", ipver, ipstr);
}
freeaddrinfo(res); // free the linked list
return 0;
}
让我感到困惑的部分是 for 循环。
for(p = res; p != NULL; p = p->ai_next) {
void *addr;
char *ipver;
// get the pointer to the address itself,
// different fields in IPv4 and IPv6:
if (p->ai_family == AF_INET) { // IPv4
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
addr = &(ipv4->sin_addr);
ipver = "IPv4";
} else { // IPv6
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
addr = &(ipv6->sin6_addr);
ipver = "IPv6";
}
// convert the IP to a string and print it:
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
printf(" %s: %s\n", ipver, ipstr);
}
有人会介意逐步了解正在发生的事情或这些事情是什么吗?它是通过链表迭代吗?..我对什么是 struct addrinfo
有一个大概的了解,但是 struct *res
和 struct *p 到底是什么
或 void *addr
和 *char ipversion
。
最佳答案
首先,你知道什么是linked list吗?是?如果你理解了这一点,你就会知道 for 循环是怎么回事。 p
是指向结构的指针,该结构还引用(链接)列表中的下一个结构。因此,您正在遍历这些结构的列表,这些结构是 addrinfo
结构。 4
现在,关于网络数据包,您需要了解的一点是它们由 header 组成。特别是 Ethernet frame .这是硬件到硬件协议(protocol)。它让您可以在物理的、有界的网络上四处走动,但对跨越物理网络边界的路由一无所知。
接下来是 tcp或者可能是另一个传输层协议(protocol),它位于两个级别之间。 TCP 与 UDP 与 X 是关于如何管理数据包的——例如,TCP 需要按顺序重新组装数据包,而 UDP 是一种“广播”类型的协议(protocol)。
最后,您拥有互联网协议(protocol)套件(IPv4、IPv6)。这些是控制更广泛意义上的路由的更高级别的协议(protocol),因此他们了解整个互联网,但对到达那里所需的步骤知之甚少。
一个很好的解释是这个 page 上的方便图表.要完成图片,BGP路由器就是这样知道如何移动东西的。
tcp/udp 通过成为(封装在)相关协议(protocol)(例如 IPv4)的一部分来适应这幅图
因此以太网帧包含其他协议(protocol),最著名的是 IPv4,其中包含路由器需要通过互联网(跨多个物理网络)将其传送出去的信息。 互联网 协议(protocol)指定了您想去哪里,从哪里开始。因此,一个典型的 IPv4 主体在其整个传输过程中保持不变,但每次它穿过物理网络时,它都会被包裹在不同的以太网数据包中。
现在,在以太网 header 中有一个字段用于查找“以太网主体”包含的内容。这一行:
if (p->ai_family == AF_INET) {
是的。 AF_INET
是一个常量,与 tcp 用于将数据包主体标识为 IPv4 的值相匹配。因此,如果您正在查看 IPv4 header ,则此循环会继续读取该信息。
else 子句技术上是错误的,因为不是 IPv4 不会自动使其成为 IPv6。您可以像这样更改它以测试 IPv6:
else if (p->ai_family == AF_INET6) {
您可能想这样做,以防万一您拿起其他东西。
现在有必要解释一下这个魔法:
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
这基本上采用以字节序列形式出现的数据的网络或原始形式,并将其转换(隐藏)到结构中的字段中。因为您知道字段有多大,所以这是提取所需内容的一种非常快速和简单的方法。
最后需要解释的是:
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
还有其他方法可以实现这一点,特别是 ntohs()
。
基本上网络数据是以大端编码传输的,为了读取它,您(可能)需要将数据转换为您系统的编码。它可以是大端,也可以是小端,这在很大程度上取决于您的系统。阅读有关 endianness 的维基百科文章.
总结:您在这里看到的是计算机科学结构、网络工作原理和 C 代码的组合。
关于c - "Network programming"示例中的这段代码如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5041926/
我认为这个问题说明了一切,但我有一个使用 .net 安装工具包的应用程序(在 vs.2005 中),并且用户问我是否可以将它安装在 c:\Program Files\ProgramName 而不是C:
这个问题不太可能帮助任何 future 的访问者;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况有关,这些情况并不普遍适用于互联网的全局受众。为了帮助使这个问题更广泛地适用,visit
我是 Stephen Wolfram 的忠实粉丝,但他绝对是一个不怕自吹自擂的人。在许多引用资料中,他将 Mathematica 颂扬为一种不同的符号编程范式。我不是 Mathematica 用户。
我现在正在使用 Squeak4.1 学习 SmallTalk。我使用 Squeak by Example 作为教程,在这里我反驳了一个 delema,“Morphic 是由...开发的,用于自编程语言
Wikipedia有话要说: Total functional programming (also known as strong functional programming, to be cont
在阅读 Paul Graham's Essays 时, 我对 Lisp 越来越好奇了。 在this article ,他提到最强大的功能之一是您可以编写可以编写其他程序的程序。 我无法在他的网站或其他
我知道 functional programming 有几个定义。 .我认为这是一个模糊的类别。我个人的定义是接近' referential transparency '。 这个问题不是“函数式编程的
我注意到许多顶尖大学都开设了类(class),在这些类(class)中,学生将学习与计算机图形学相关的 CS 专业科目。可悲的是,这是我的大学没有提供的东西,我真的很想在 future 几年的某个时候
我正在安装100%托管代码的.NET(C#)应用程序。安装程序(InnoSetup)始终希望将应用程序安装到Vista x64中的“Program Files(x86)”文件夹中,我认为这是因为安装程
假设在 C 中,我们有以下结构: struct MyData { char key1[20]; long key2; ... /* some data */ }; 本质上,除
这个问题已经有答案了: When should I use ampersand with scanf() (3 个回答) 已关闭 6 年前。 所以我在python3中有这个“程序”,它添加了3个字符串
我编写了一个包含 self 更新程序的 Java 应用程序。自更新程序从 Web 服务器加载新的程序版本并替换应用程序文件。如果安装了应用程序,这将完美地工作,例如在用户主目录中,如果它安装在 C:\
注意:标记为社区维基。 是否有一个很好的分析为什么可视化编程语言仍然没有起飞?这些天我们仍在 80x25 文本窗口中“线性”编码;而我们表示的概念(数据结构、算法)似乎可以更直观地表示出来。 最佳答案
我一直在阅读Code Complete 2 .由于我不是以英语为母语的人,因此我需要一些时间才能理解某些陈述。我希望你描述作者在他的书中所做的这两个陈述之间的区别: You should progra
我在为我的 tomcat 设置 CLASSPATH 时遇到了这个问题。我需要在 tomcat 的 CLASSPATH 中引用我的 2 个安装。其中一个位于 C:\Program Files\Postg
这个问题已经有答案了: How can I lock a file using java (if possible) (8 个回答) 已关闭 6 年前。 我有 2-3 个程序可以修改文件,但如果有一个
我 checkout Reading stdout from one program in another program却没有找到我要找的答案 我是 Linux 的新手,我正在使用 Python 中
我有一个程序可以打印出通过或失败。我想检测卡在那里的程序并回显“超时” 我写了这样一个脚本: #!/bin/bash echo -n 'test' && timeout 5 ./mytest | gr
我非常清楚函数式编程技术和命令式编程技术之间的区别。但是现在有一种普遍的趋势是谈论“函数式语言”,这确实让我感到困惑。 当然,像 Haskell 这样的一些语言比 C 等其他语言更欢迎函数式编程。但即
请求:每个进程需要计算自己的组到所有点的距离。我的代码如下: #include stdio.h #include stdlib.h #include math.h #include string.h
我是一名优秀的程序员,十分优秀!