在印尼用哪个网站做电商,石家庄造价工程信息网,广州网站建设好做吗,海淀营销型网站建设大家好#xff0c;我是码农先森。
前言
各种编程语言百花齐放、百家争鸣#xff0c;但是 “万变不离其中”。对于网络通信而言#xff0c;每一种编程语言的实现方式都不一样#xff1b;但其实#xff0c;调用的底层逻辑都是一样的。linux 系统底层向上提供了统一的 Sock…大家好我是码农先森。
前言
各种编程语言百花齐放、百家争鸣但是 “万变不离其中”。对于网络通信而言每一种编程语言的实现方式都不一样但其实调用的底层逻辑都是一样的。linux 系统底层向上提供了统一的 Socket 通信系统函数动态链接库 /lib64/libc.so 中就是实现网络通信的关键类库。下面我们会以 Go 语言为例来分析网络通信数据传输的路径最终揭开各大编程语言网络通信的神秘面纱。
演示程序
1、使用 Go 编写一个简单的 Socket 程序
package mainimport (fmtnet
)func main() {// 监听本地端口listener, err : net.Listen(tcp, :8080)if err ! nil {fmt.Println(Error listening:, err.Error())return}defer listener.Close()fmt.Println(Listening on localhost:8080)for {// 接收客户端连接conn, err : listener.Accept()if err ! nil {fmt.Println(Error accepting:, err.Error())return}// 处理客户端请求go handleRequest(conn)}
}func handleRequest(conn net.Conn) {// 读取请求数据buffer : make([]byte, 1024)n, err : conn.Read(buffer)if err ! nil {fmt.Println(Error reading:, err.Error())return}// 处理请求数据message : string(buffer[:n])fmt.Println(Received message:, message)// 发送响应数据reply : Hello, client!conn.Write([]byte(reply))// 关闭连接conn.Close()
}2、编译成二进制文件。
go build main.go
[yxhdev01 demo]$ ls -l
total 2536
-rwxr-xr-x 1 yangxionghai devops 2590837 Jun 2 15:42 main
-rw-r--r-- 1 yangxionghai devops 1023 Jun 2 15:39 main.go3、执行 main 二进制文件
[yxhdev01 demo]$ ./main
Listening on localhost:8080跟踪进程数据
1、跟踪 main 进程
# 找到进程ID
[yxhdev01 demo]$ ps -aux | grep main
yxh 32270 0.0 0.0 816460 1732 pts/3 Sl 16:47 0:00 ./main
yxh 32404 0.0 0.0 112816 968 pts/13 S 16:47 0:00 grep --colorauto main2、使用 strace 跟踪进程
strace -f -s 2048 -i -T -o trace.log -p 32270命令各参数的解释
-f: 跟踪在运行时从父进程派生出来的子进程包括进程创建和退出等操作。
-s: 指定在输出中显示的字符串的最大长度为 2048 字节这样可以避免过长的输出导致日志文件过大。
-i: 在输出中同时显示系统调用的入口和返回地址。
-T: 在输出中显示每个系统调用花费的时间。
-o: 将输出的结果写入到名为 trace.log 的文件中而不是输出到控制台。
-p: 指定要跟踪的进程 ID 是 32270。3、使用 telnet 发生数据
# 客户端发送数据
[yxhdev01 ~]$ telnet 127.0.0.1 8080
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is ^].
^]telnet
# 客户端发生的数据
hello world
# 服务端返回的数据
Hello, client!
Connection closed by foreign host.4、服务端接收到数据
# 服务端接收到数据
[yxhdev01 demo]$ ./main
Listening on localhost:8080
Received message: hello world深度分析
1、分析跟踪信息
我们先分析刚刚使用 strace 工具跟踪到的信息可以看到里面有很多的系统调用。具体每个系统函数的说明及用法可以去搜索引擎上查找资料学习。
# 跟踪到的信息
[yxhdev01 demo]$ cat trace.log
32275 [0000000000462943] futex(0x5e0058, FUTEX_WAIT_PRIVATE, 0, NULL unfinished ...
32274 [0000000000462943] futex(0xc000080150, FUTEX_WAIT_PRIVATE, 0, NULL unfinished ...
32273 [0000000000462943] futex(0xc000044d50, FUTEX_WAIT_PRIVATE, 0, NULL unfinished ...
32272 [0000000000462943] futex(0xc000044950, FUTEX_WAIT_PRIVATE, 0, NULL unfinished ...
32271 [0000000000462943] restart_syscall(... resuming interrupted restart_syscall ... unfinished ...
32270 [0000000000462b60] epoll_pwait(5, unfinished ...
32271 [0000000000462943] ... restart_syscall resumed) -1 ETIMEDOUT (Connection timed out) 25.495631
32271 [00000000004623bd] nanosleep({tv_sec0, tv_nsec20000}, NULL) 0 0.000107
32271 [0000000000462943] futex(0x5b1bd8, FUTEX_WAIT_PRIVATE, 0, {tv_sec60, tv_nsec0}) -1 ETIMEDOUT (Connection timed out) 60.000108
32271 [00000000004623bd] nanosleep({tv_sec0, tv_nsec20000}, NULL) 0 0.000100
32271 [0000000000462943] futex(0x5b1bd8, FUTEX_WAIT_PRIVATE, 0, {tv_sec60, tv_nsec0}) -1 ETIMEDOUT (Connection timed out) 60.000112
32271 [00000000004623bd] nanosleep({tv_sec0, tv_nsec20000}, NULL) 0 0.000123
32271 [0000000000462943] futex(0x5b1bd8, FUTEX_WAIT_PRIVATE, 0, {tv_sec60, tv_nsec0} unfinished ...
32270 [0000000000462b60] ... epoll_pwait resumed[{EPOLLIN, {u322087155416, u64140464697603800}}], 128, -1, NULL, 0) 1 188.828350
32270 [0000000000462943] futex(0x5b1bd8, FUTEX_WAKE_PRIVATE, 1) 1 0.000028
32271 [0000000000462943] ... futex resumed) 0 43.331766
32270 [000000000047f08a] accept4(3, unfinished ...
32271 [00000000004623bd] nanosleep({tv_sec0, tv_nsec20000}, unfinished ...
32270 [000000000047f08a] ... accept4 resumed{sa_familyAF_INET6, sin6_porthtons(9622), inet_pton(AF_INET6, ::ffff:127.0.0.1, sin6_addr), sin6_flowinfohtonl(0), sin6_scope_id0}, [112-28], SOCK_CLOEXEC|SOCK_NONBLOCK) 4 0.000019
32271 [00000000004623bd] ... nanosleep resumedNULL) 0 0.000076
32270 [0000000000462b38] epoll_ctl(5, EPOLL_CTL_ADD, 4, {EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, {u322087155184, u64140464697603568}} unfinished ...
32271 [00000000004623bd] nanosleep({tv_sec0, tv_nsec20000}, unfinished ...
32270 [0000000000462b38] ... epoll_ctl resumed) 0 0.000017
32270 [000000000047f0f6] getsockname(4, {sa_familyAF_INET6, sin6_porthtons(8080), inet_pton(AF_INET6, ::ffff:127.0.0.1, sin6_addr), sin6_flowinfohtonl(0), sin6_scope_id0}, [112-28]) 0 0.000017
32270 [000000000047f08a] setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4 unfinished ...
32271 [00000000004623bd] ... nanosleep resumedNULL) 0 0.000103
32270 [000000000047f08a] ... setsockopt resumed) 0 0.000016
32271 [00000000004623bd] nanosleep({tv_sec0, tv_nsec20000}, unfinished ...
32270 [000000000047f08a] setsockopt(4, SOL_SOCKET, SO_KEEPALIVE, [1], 4) 0 0.000017
32270 [000000000047f08a] setsockopt(4, SOL_TCP, TCP_KEEPINTVL, [15], 4) 0 0.000017
32271 [00000000004623bd] ... nanosleep resumedNULL) 0 0.000090
32270 [000000000047f08a] setsockopt(4, SOL_TCP, TCP_KEEPIDLE, [15], 4 unfinished ...
32271 [00000000004623bd] nanosleep({tv_sec0, tv_nsec20000}, unfinished ...
32270 [000000000047f08a] ... setsockopt resumed) 0 0.000016
32270 [0000000000462943] futex(0xc000080150, FUTEX_WAKE_PRIVATE, 1) 1 0.000020
32274 [0000000000462943] ... futex resumed) 0 188.828982
32270 [000000000047f08a] accept4(3, unfinished ...
32274 [0000000000462b60] epoll_pwait(5, unfinished ...
32271 [00000000004623bd] ... nanosleep resumedNULL) 0 0.000101
32274 [0000000000462b60] ... epoll_pwait resumed[{EPOLLOUT, {u322087155184, u64140464697603568}}], 128, 0, NULL, 0) 1 0.000014
32270 [000000000047f08a] ... accept4 resumed0xc000053c10, [112], SOCK_CLOEXEC|SOCK_NONBLOCK) -1 EAGAIN (Resource temporarily unavailable) 0.000037
32274 [0000000000462943] futex(0xc000044950, FUTEX_WAKE_PRIVATE, 1 unfinished ...
32271 [00000000004623bd] nanosleep({tv_sec0, tv_nsec20000}, unfinished ...
32274 [0000000000462943] ... futex resumed) 1 0.000018
32270 [0000000000462b60] epoll_pwait(5, unfinished ...
32274 [000000000047f01b] read(4, unfinished ...
32272 [0000000000462943] ... futex resumed) 0 188.829100
32274 [000000000047f01b] ... read resumed0xc00008e400, 1024) -1 EAGAIN (Resource temporarily unavailable) 0.000017
32270 [0000000000462b60] ... epoll_pwait resumed[], 128, 0, NULL, 2) 0 0.000039
32274 [0000000000462b60] epoll_pwait(5, unfinished ...
32272 [0000000000462b60] epoll_pwait(5, unfinished ...
32274 [0000000000462b60] ... epoll_pwait resumed[], 128, 0, NULL, 2) 0 0.000019
32271 [00000000004623bd] ... nanosleep resumedNULL) 0 0.000120
32270 [0000000000462b60] epoll_pwait(5, unfinished ...
32274 [0000000000462943] futex(0xc000080150, FUTEX_WAIT_PRIVATE, 0, NULL unfinished ...
32272 [0000000000462b60] ... epoll_pwait resumed[], 128, 0, NULL, 0) 0 0.000054
32271 [00000000004623bd] nanosleep({tv_sec0, tv_nsec20000}, unfinished ...
32272 [0000000000462943] futex(0xc000044950, FUTEX_WAIT_PRIVATE, 0, NULL unfinished ...
32271 [00000000004623bd] ... nanosleep resumedNULL) 0 0.000112
32271 [0000000000462943] futex(0x5b1bd8, FUTEX_WAIT_PRIVATE, 0, {tv_sec60, tv_nsec0} unfinished ...
32270 [0000000000462b60] ... epoll_pwait resumed[{EPOLLIN|EPOLLOUT, {u322087155184, u64140464697603568}}], 128, -1, NULL, 0) 1 8.305983
32270 [0000000000462943] futex(0x5b1bd8, FUTEX_WAKE_PRIVATE, 1 unfinished ...
32271 [0000000000462943] ... futex resumed) 0 8.305878
32270 [0000000000462943] ... futex resumed) 1 0.000035
32271 [0000000000462aa7] sched_yield( unfinished ...
32270 [000000000047f01b] read(4, unfinished ...
32271 [0000000000462aa7] ... sched_yield resumed) 0 0.000015
# 接收到来自客户端的数据
32270 [000000000047f01b] ... read resumedhello world\r\n, 1024) 13 0.000015
32271 [0000000000462943] futex(0x5b1ad8, FUTEX_WAKE_PRIVATE, 1) 0 0.000021
32271 [00000000004623bd] nanosleep({tv_sec0, tv_nsec20000}, unfinished ...
32270 [000000000047f01b] write(1, Received message: hello world\r\n\n, 32) 32 0.000025
# 服务端返回给客户端的数据
32270 [000000000047f01b] write(4, Hello, client!, 14 unfinished ...
32271 [00000000004623bd] ... nanosleep resumedNULL) 0 0.000092
32271 [00000000004623bd] nanosleep({tv_sec0, tv_nsec20000}, unfinished ...
32270 [000000000047f01b] ... write resumed) 14 0.000040
32270 [0000000000462b38] epoll_ctl(5, EPOLL_CTL_DEL, 4, 0xc00004ee3c unfinished ...
32271 [00000000004623bd] ... nanosleep resumedNULL) 0 0.000092
32270 [0000000000462b38] ... epoll_ctl resumed) 0 0.000067
32271 [00000000004623bd] nanosleep({tv_sec0, tv_nsec20000}, unfinished ...
32270 [000000000047f01b] close(4) 0 0.000033
32270 [0000000000462b60] epoll_pwait(5, [], 128, 0, NULL, 824634044416) 0 0.000017
32271 [00000000004623bd] ... nanosleep resumedNULL) 0 0.000101
32270 [0000000000462b60] epoll_pwait(5, unfinished ...
32271 [0000000000462943] futex(0x5b1bd8, FUTEX_WAIT_PRIVATE, 0, {tv_sec60, tv_nsec0}) -1 ETIMEDOUT (Connection timed out) 60.000106
32271 [00000000004623bd] nanosleep({tv_sec0, tv_nsec20000}, NULL) 0 0.000116
32271 [0000000000462943] futex(0x5b1bd8, FUTEX_WAIT_PRIVATE, 0, {tv_sec60, tv_nsec0}) -1 ETIMEDOUT (Connection timed out) 60.000107
32271 [00000000004623bd] nanosleep({tv_sec0, tv_nsec20000}, NULL) 0 0.000119strace 命令是 Linux 系统下的一个系统调用跟踪工具其主要作用是打印出程序执行时调用的所有系统调用以及相应的返回值。 2、分析 main 编译的可执行二进制文件
使用 ldd 查看二进制文件的动态链接调用库。
[yxhdev01 demo]$ ldd mainlinux-vdso.so.1 (0x00007ffd761d2000)libpthread.so.0 /lib64/libpthread.so.0 (0x00007f6cb5857000)# libc.so 库的主要作用是为开发者提供一些常用的、通用的基础函数例如字符串处理、文件操作、进程管理、网络通信等同时也提供了一些系统调用的封装接口。libc.so.6 /lib64/libc.so.6 (0x00007f6cb5489000)/lib64/ld-linux-x86-64.so.2 (0x00007f6cb5a73000)ldd 命令是 Linux 系统下的一个动态链接库依赖检查工具用于显示可执行程序或共享库文件所依赖的动态链接库列表。 分析 libc.so 动态链接库
[yxhdev01 demo]$ nm /lib64/libc.so.6 | grep read
000000000010c550 W pthread_setcancelstate
000000000010c580 T pthread_setcanceltype
000000000010c430 T pthread_setschedparam
000000000013e6c0 t __pthread_unwind
# 读函数
00000000000ef990 W read
00000000000ef990 W __read
00000000000fe9a0 W readahead
00000000000fe9a0 t __readahead
0000000000033180 t read_alias_file[yxhdev01 demo]$ nm /lib64/libc.so.6 | grep write
00000000000f5510 T pwritev
00000000000f5510 T pwritev64
# 写函数
00000000000ef9f0 W write
00000000000ef9f0 W __write
0000000000100250 t write_gmon
00000000000ef9f9 t __write_nocancel
00000000001009a0 t __write_profiling
000000000012f440 t writetcpnm 是一个 Linux 系统下的二进制文件分析工具用于查看目标文件或者可执行文件的符号表信息以及相关的重定位信息等。 除了 read、write 还有 accept、sendto、recvfrom、setsockopt、getsockopt、epoll 等函数。
总结
唯一不变的是变化新技术层出不穷。对于我们技术人来说不断学习新的技术是永无止境的时间长了会陷入疲惫不堪。我们只有在不断变化中 “寻找不变化的东西”通过掌握本质的东西来以不变来应万变。这篇文章以 Go 语言为例来逐步的从应用层到系统层的跟踪剖析挖掘网络通信的本质深入了解 Socket 通信的底层逻辑。希望大家可以以本文中的 Go 语言为例举一反三。如果有什么问题可以评论留言。 欢迎关注、分享、点赞、收藏、在看我是微信公众号「码农先森」作者。 文章转载自: http://www.morning.mwwnz.cn.gov.cn.mwwnz.cn http://www.morning.nlgmr.cn.gov.cn.nlgmr.cn http://www.morning.rqxmz.cn.gov.cn.rqxmz.cn http://www.morning.hwljx.cn.gov.cn.hwljx.cn http://www.morning.lyldhg.cn.gov.cn.lyldhg.cn http://www.morning.kbqws.cn.gov.cn.kbqws.cn http://www.morning.bmzxp.cn.gov.cn.bmzxp.cn http://www.morning.dtrcl.cn.gov.cn.dtrcl.cn http://www.morning.brscd.cn.gov.cn.brscd.cn http://www.morning.rmqlf.cn.gov.cn.rmqlf.cn http://www.morning.rrwgh.cn.gov.cn.rrwgh.cn http://www.morning.ylpl.cn.gov.cn.ylpl.cn http://www.morning.pbwcq.cn.gov.cn.pbwcq.cn http://www.morning.gxhqt.cn.gov.cn.gxhqt.cn http://www.morning.xlmpj.cn.gov.cn.xlmpj.cn http://www.morning.mksny.cn.gov.cn.mksny.cn http://www.morning.yhxhq.cn.gov.cn.yhxhq.cn http://www.morning.wjfzp.cn.gov.cn.wjfzp.cn http://www.morning.trlhc.cn.gov.cn.trlhc.cn http://www.morning.glswq.cn.gov.cn.glswq.cn http://www.morning.mdjtk.cn.gov.cn.mdjtk.cn http://www.morning.rgpbk.cn.gov.cn.rgpbk.cn http://www.morning.mgbsp.cn.gov.cn.mgbsp.cn http://www.morning.jqkrt.cn.gov.cn.jqkrt.cn http://www.morning.qdlr.cn.gov.cn.qdlr.cn http://www.morning.tygn.cn.gov.cn.tygn.cn http://www.morning.sjmxh.cn.gov.cn.sjmxh.cn http://www.morning.qqtzn.cn.gov.cn.qqtzn.cn http://www.morning.jtybl.cn.gov.cn.jtybl.cn http://www.morning.zcrjq.cn.gov.cn.zcrjq.cn http://www.morning.zcnfm.cn.gov.cn.zcnfm.cn http://www.morning.gjlst.cn.gov.cn.gjlst.cn http://www.morning.fpqq.cn.gov.cn.fpqq.cn http://www.morning.qmwzz.cn.gov.cn.qmwzz.cn http://www.morning.nbybb.cn.gov.cn.nbybb.cn http://www.morning.ybgt.cn.gov.cn.ybgt.cn http://www.morning.pwrkl.cn.gov.cn.pwrkl.cn http://www.morning.drmbh.cn.gov.cn.drmbh.cn http://www.morning.qqhfc.cn.gov.cn.qqhfc.cn http://www.morning.qcwrm.cn.gov.cn.qcwrm.cn http://www.morning.rtryr.cn.gov.cn.rtryr.cn http://www.morning.nqrdx.cn.gov.cn.nqrdx.cn http://www.morning.qnftc.cn.gov.cn.qnftc.cn http://www.morning.trmpj.cn.gov.cn.trmpj.cn http://www.morning.wmmjw.cn.gov.cn.wmmjw.cn http://www.morning.jkdtz.cn.gov.cn.jkdtz.cn http://www.morning.sdkaiyu.com.gov.cn.sdkaiyu.com http://www.morning.sloxdub.cn.gov.cn.sloxdub.cn http://www.morning.gkxyy.cn.gov.cn.gkxyy.cn http://www.morning.lngyd.cn.gov.cn.lngyd.cn http://www.morning.jqhrk.cn.gov.cn.jqhrk.cn http://www.morning.c7622.cn.gov.cn.c7622.cn http://www.morning.bxczt.cn.gov.cn.bxczt.cn http://www.morning.nchlk.cn.gov.cn.nchlk.cn http://www.morning.tzjqm.cn.gov.cn.tzjqm.cn http://www.morning.qhczg.cn.gov.cn.qhczg.cn http://www.morning.qrwdg.cn.gov.cn.qrwdg.cn http://www.morning.kgqpx.cn.gov.cn.kgqpx.cn http://www.morning.kgltb.cn.gov.cn.kgltb.cn http://www.morning.bqqzg.cn.gov.cn.bqqzg.cn http://www.morning.tnyanzou.com.gov.cn.tnyanzou.com http://www.morning.jcypk.cn.gov.cn.jcypk.cn http://www.morning.sqdjn.cn.gov.cn.sqdjn.cn http://www.morning.qnrpj.cn.gov.cn.qnrpj.cn http://www.morning.zqfz.cn.gov.cn.zqfz.cn http://www.morning.ktntj.cn.gov.cn.ktntj.cn http://www.morning.qynnw.cn.gov.cn.qynnw.cn http://www.morning.zmqb.cn.gov.cn.zmqb.cn http://www.morning.pcxgj.cn.gov.cn.pcxgj.cn http://www.morning.mrckk.cn.gov.cn.mrckk.cn http://www.morning.zlff.cn.gov.cn.zlff.cn http://www.morning.tkzrh.cn.gov.cn.tkzrh.cn http://www.morning.kwyq.cn.gov.cn.kwyq.cn http://www.morning.kgxrq.cn.gov.cn.kgxrq.cn http://www.morning.jtwck.cn.gov.cn.jtwck.cn http://www.morning.qpmwb.cn.gov.cn.qpmwb.cn http://www.morning.ghgck.cn.gov.cn.ghgck.cn http://www.morning.cgtfl.cn.gov.cn.cgtfl.cn http://www.morning.nqwkn.cn.gov.cn.nqwkn.cn http://www.morning.ghrlx.cn.gov.cn.ghrlx.cn