golang tcp keepalive

缘起: grpc-client 连接 grpc-server后,空闲连接的情况下,server端会每隔15s向client发送一个keepalive数据包; 从grpc-server的配置中没有找到这个15s的配置,有的只是一个2小时发送一次的应用层的ping包。为啥呢?

分析:

  1. 该数据包可能是系统自己发送的,查看一下sysctl -a|grep tcp |grep keepalive 如下:
    按照这个配置,应该是75s一次才对,和实际的15s不符;难道不是系统发出来的?
  2. kill -19 PID后,发现间隔15s的数据包依然发送,说明肯定是系统发出来的
  3. 由于MacOS上的netstat 无法查看连接的Timer信息,于是使用Linux进行测试,发现keepalive的timer果然是从15s递减至0后就会发送该数据包(这里还发现当时间小于10s时,ss显示的时间单位是错的,把s写成了ms)。
  4. 一定是golang设置了一个和系统默认值不一样的keepalive; 那么是在什么时候设置的呢?从server端的Accept看起吧,发现Listen的时候有一个无法自定义的ListenerConfig,这里面有

 

 

@ net/dialog.go

Listen的时候,KeepAlive是0值,但是在newTcpConn的时候,检测如果是0值,就参考下面的默认值。

@ net/tcpsock.go

 

其实,在grpc/server.go 的grpc.Server.Serve()方法中已经特别说明了这个事情(而且仅就此问题做了说明):

容器的1号进程果然不一般

现象:

  1. 你无法kill掉容器的1号进程,包括kill -11  kill -6  ,包括 kill -9,因为内核对于进程空间的1号进程是特殊对待的,不会安装默认信号处理程序。
  2. 如果你的进程是容器中的1号进程,那么在进程崩溃的时候,是不会有coredump文件产生的。

 

Hi folks,
I have looked into this issue and I want to share the results of my investigation, which turned out to be quite intriguing.

The contained application has PID 1, which means that the Linux kernel treats it as a standalone init process for this namespace. The Linux kernel handles signals differently for the init process than it does for other processes. Signal handlers are not automatically registered for this process, meaning that signals will not take effect by default.
Since the contained application does not have user-defined signal handlers and the kernel does not register the default ones, the SIGABRT signal sent by the abort function is not handled at all.
In this situation, abort tries to kill the application by executing a forbidden asm instruction “HLT”. As a result, the CPU sets the GPF interruption and the kernel kills the contained application with SIGSEGV, which leads to the exit code 139. Docker just sets its exit code accordingly.

The easiest way to make the contained application to have the default signal handlers is to run docker with the flag –init.

For an expanded explanation on how signals are handled in a docker container, I have provided a detailed answer with visual examples in my article.

Perhaps we should expand the description in https://github.com/docker/cli/blob/v20.10.2/docs/reference/run.md#foreground and/or link to that post. Currently it mentions;

Note

A process running as PID 1 inside a container is treated specially by Linux:
it ignores any signal with the default action. As a result, the process will
not terminate on SIGINT or SIGTERM unless it is coded to do so.

Contributions welcome if someone is interested.

参考:

Docker container exit code is zero when program is terminated with SIGSEGV · Issue #41454 · moby/moby (github.com)

Docker container exit code has unexpected value when program aborts · Issue #30593 · moby/moby (github.com)

How signals are handled in a docker container | Dmitry Danilov (ddanilov.me)

Exit codes in docker when a program aborts | Dmitry Danilov (ddanilov.me)

顶级域名都有哪些

View the Public Suffix List

Public Suffix List

publicsuffix/list: The Public Suffix List (github.com)

要实现一个http client,可能就会涉及cookiejar,这就需要了解cookie的存储,就和域名有关系,你不能把 a.com.cn 和 a.cn 的cookie都存到 .cn下面,因为.cn 是个顶级域名;也不能把 a.com.cn 好 b.com.cn 的cookie都存在.com.cn 下面,因为.com.cn也是个顶级域名;但是1.a.cn 和 2.a.cn 这两个域名的cookie就可以都设置在 a.cn下面,因为这个a.cn 不是顶级域名。没有一个算法快速判断哪个域名是否顶级域名,只能把所有顶级域名都存起来,就是上面的public suffix list,比如,golang中就有一个net.publicsuffix ,这个是硬编码的。

eTLD: effective top level domain

Qq

天气通 – 关注天气,开启美好生活 来自 Weibo Internet Technology (China) Co.Ltd.

天气通 – 关注天气,开启美好生活 来自 Weibo Internet Technology (China) Co.Ltd.

 

https://apps.apple.com/cn/app/%E5%A4%A9%E6%B0%94%E9%80%9A-%E5%85%B3%E6%B3%A8%E5%A4%A9%E6%B0%94-%E5%BC%80%E5%90%AF%E7%BE%8E%E5%A5%BD%E7%94%9F%E6%B4%BB/id458032309

 

 

-fvisibility=hidden 测试

man gcc

gcc 编译时,如果使用了 -fvisibility=hidden 选项,编译的so文件中的函数默认是不导出的,就是动态链接是链接不到的;不仅有隐藏的效果(使用nm还是能看到的,所以,该选项不是出于安全考虑,主要是实现private的效果),也有利于编译器的进一步优化。由于历史代码可能不期望这个行为,所以该选项也不是默认行为(好像在object-c中是默认行为)。

下面测试一下:

main

 

f.h

这个头文件太简单了🤦‍♀️

 

libf.c

 

编译main.c

编译libf.c