JasonWang's Blog

JasonWang's Blog

聊一聊TCP协议

TCP(Transmission Control Protocol)即传输控制协议, 位于TCP/IP协议栈的第三层传输层, 与UDP不同的是, TCP号称提供有链接的(connection-oriented), 可靠的(reliable)字节流服务, 很多其他应用层协议如HTTP/SMTP/MQTT都是基于TCP协议实现.

这篇文章我们就从定义的角度来看一看TCP协议的具体工作原理. 首先看下有链接的(connection-oriented)具体含义.

TCP在发送数据之前, 第一件事情就是要在通信的双方建立一个通信的链路, 这个有点像日常生活中的打电话: A向B发起通话请求, B确认后双方建立通信链接才能正式通话. TCP也一样, 在发送任何数据之前必须要建立链接(connection), 这个建立通信链接的过程就是我们常说的”三次握手”;同样, 如果要想结束通信, 也需要有一个挥手的过程(四次挥手).有关TCP链接的建立与关闭可以参考之前的一篇文章(TCP的链接建立与状态迁移). 那么, TCP建立链接主要完成哪几件事情了?

TCP链接建立与状态迁移

学习TCP协议的第一步是要了解熟悉TCP的三次握手/四次挥手以及状态迁移图. 这篇文章用三个图展示TCP链接的建立与关闭以及状态的迁移.

TCP状态迁移

根据TCP协议的文档RFC793, 一个TCP链接有下图中的几个状态(图中实粗线为Client端的正常情况下状态迁移图, 虚线为Server端正常情况下的状态迁移图):

  • CLOSED: TCP链接的初始状态, 表示没有任何链接
  • LISTEN: (服务端)等待来自远程客户端的请求
  • SYN_SENT: 发送了一个建立TCP链接的SYN请求, 等待对端返回结果
  • SYN_RCVD: 收到了TCP建立链接的SYN包, 等待对方的回应(ACK)
  • ESTABLISHED: TCP链接建立成功, 从这里开始可以交换数据包了
  • FIN_WAIT1: 应用进程关闭了TCP链接(发送FIN包), 并等待对端的响应
  • FIN_WAIT2: 接收到关闭回应后, 等待对端结束TCP链接(等待FIN包)
  • CLOSING: 如果两端同时接收到了FIN包, 则进入该状态
  • CLOSE_WAIT:处于被动关闭一端接受到FIN请求后, 等待本地进程的关闭TCP链接
  • LAST_ACK: 服务端本地进程关闭TCP链接后, 发送FIN包, 等待回应
  • TIME_WAIT: 等待2*MSL(Maximum Segment Lifetime, TCP包的最大存活时间)后关闭该TCP链接, 等待足够长的时间是为了确保最后关闭链接的ACK包有足够长的时间达到对端, 如果对端未能收到该包, 则会重传FIN包, 这样对端也可以重传ACK包, 一般MSL为60s。有关更多TIME_WAIT状态的解释可以参考TIME-WAIT State.

TCP state transition

PPP拨号时拿到错误DNS的问题解析

最近碰到一个PPP拨号拿到了假的DNS地址10.11.12.13/14, 之前也发生过一次, 但是一直没有有效的日志, 所以就简单粗暴的做了一个方案: 在PPP拨号进行网络参数协商时, 如果发现拿到了10.11.12.13/14这样的DNS地址就修改为指定的运营商DNS地址. 本来以为万事大吉了, 没想到运营商DNS一改, 问题又暴露了, 好在重现抓到了现场日志, 终于找到了原因. 网上看有原来也有不少人碰到了类似现象(https://bugzilla.redhat.com/show_bug.cgi?id=467004#c31), 在这里简要的描述下整个问题的来龙去脉并给出几种可能的解决方案.

在介绍这个问题的根因之前, 先来了解下PPP协议的一些基本概念.

PPP协议介绍

PPP(Point-to-Point Protocol)是在SLIP(Serial Line Internet Protocol)的基础上发展而来, 其通过在终端与远端(remote peer)之间建立一个IPPP数据链路, 将终端设备接入网络. 早些年上网的时候, 把一个ADSL modem跟电脑连接后, 拿着运营商给的用户名与密码, 然后拨号接入互联网,这里边用到的协议就是PPP.

如何在Android Studio中添加自定义framework.jar?

这两天有一个新的功能需求要实现, 要在Android原生代码的Settings(代码目录android/frameworks/base/core/java/android/provider)数据库添加一个新的数据项, 一个系统应用(独立于Android系统源码编译)需要引用该数据项. 那么, 怎么将新的数据项引用到系统应用中了? <! – more –>

备注: 以下所有的示例都基于Android Studio 3.2/操作系统Ubuntu 18.04.1

首先, 在Android源码中修改完成后, 执行本地编译, 在/android/out目录下, 找到编译产生的新的framework模块的jar包:

1
2
out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes-full-debug.jar

Linux下常用网络工具使用总结

平时在Android/Ubuntu这样的Linux系统中, 经常跟网络打交道, 不可避免的要使用网络工具来定位问题;这里对Linux常用的网络工具进行简单的总结, 方便后续查阅使用. 主要看看以下几个常用的网络工具:

  • ping: 基于ICMP协议, 发送ICMP数据包用于测试网络连通状态
  • traceroute: 基于UDP/ICMP/TCP协议用于跟踪网络连通状态, 打印达到目标地址的路由信息
  • tcpdump : 用于抓取tcp/ip包, 分析网络问题的必需神器
  • iproute2 : 查看/添加/删除当前路由信息
  • netstat: 查看网络状态
  • netcfg: 配置网口(使能网口以及配置IP等)
  • iptables: 网络数据包的过滤以及防火墙策略配置
  • netcat: 用于快速建立TCP/UDP链接,检测网络的连通性
  • iperf: 网络性能测试工具, 用来衡量网络吞吐量/带宽
  • tc: Traffic Control, 用于显示/修改网卡配置的工具
  • curl: 基于libcurl的数据传输工具, 支持HTTP/HTTPS/FTP/RTMP/RTSP/SCP等常见协议
  • iw: 用于显示/设置WiFi设备接口的工具, 比如展示当前设备WiFi热点信息, 主动扫描周围WiFi热点等
  • ethtool: 查看/设置以太网网卡驱动/硬件配置
Android netd工作原理详解

NETD是Android一个专门管理网络链接, 路由/带宽/防火墙策略以及iptables的系统Daemon进程, 其在Anroid系统启动时加载:

1
2
3
4
5
6
7
8

service netd /system/bin/netd
class main
socket netd stream 0660 root system
socket dnsproxyd stream 0660 root inet
socket mdns stream 0660 root system
socket fwmarkd stream 0660 root inet

socket编程与IO multiplexing

socket通常用于跨进程通信(Inter-Process Communication,IPC),由于其最早BSD Unix发行版中使用,因此也叫做Barkeley sockets。socket封装了底层网络通信协议细节,为上层应用提供了一个统一的接口,按照使用的“域”不同,又分为用于网络通信的internet socket以及用于本地进程通信的Unix domain socket。

那么,如何利用socket实现IPC通信了?在多个客户端的情况下,服务端要如何实现同时响应多个客户请求了,即如何实现多个IO端口的监听(I/O multiplex)?这篇文章,就来看看这两个问题。首先,来看下socket编程的一些基本知识。

avatar
JasonWang
生命短暂,莫空手而归