linux 网络编程学习笔记(更新中...)
文章平均质量分 78
--Allen--
我知道我不知道。
展开
-
8-TCP 协议(断开连接)
这一篇,讨论的是著名的四次挥手。1. 断开连接在此之前,先看图 1,看看 TCP 是如何断开连接的. 图1 四次挥手 图 2,仍然是之前的实验中所抓取的数据包,你可以以在 unp/protocol/data/tcp_retrans.pkt 目录下找到它。 图2 抓取到的数据包 (1) 首先,由客户端调用 close,将这一端称为主动关闭(active close)。然后该端发送一个原创 2017-04-06 14:03:58 · 2387 阅读 · 0 评论 -
11-TCP 协议(状态机)
1. TCP 状态机TCP 协议太复杂了,连接的建立与终止在前面都已经有所介绍,所有的规则都可以用一张 TCP 状态变迁图来表示。 图1 TCP 状态机 这张图非常经典,网络上都可以找得到,但是这里我用彩色线条重新画了一遍。接下来就是关于图 1 的几点说明:绿色粗实线和蓝色粗虚线表示正常的状态变迁。红色细实线表示异常变迁。顶层的 CLOSED 状态是一个假想的起点和终点,并不是一个真正原创 2017-04-08 17:03:43 · 5104 阅读 · 1 评论 -
12-TCP 协议(TIME_WAIT 状态)
如果你仔细研究了 TCP 四次挥手,你会发现主动关闭一方最后的状态是 TIME_WAIT,这个 TIME_WAIT 状态是什么意思呢? 图1 仔细观察主动关闭一方最后的状态 1. TIME_WAIT 状态TIME_WAIT 状态,又称为 2MSL 等待状态。只有主动关闭一方才能进入 TIME_WAIT 状态。MSL(Maximum Segment Lifetime)表示报文段最大生存时间,它原创 2017-04-08 17:56:37 · 3217 阅读 · 1 评论 -
10-TCP 协议(MSS)
再次引用一下 TCP 首部。 图1 TCP 协议首部 1. MSS(Maximum Segment Size)MSS,最大报文段长度。在连接建立的时候,即在发送 SYN 段的时候,同时会将 MSS 发送给对方(MSS 选项只能出现在 SYN 段中!!!),告诉对端它期望接收的 TCP 报文段数据部分最大长度。MSS 保存在 TCP 首部的可选项中,图 2 中显示 MSS 的值为 1260。原创 2017-04-08 14:50:45 · 4336 阅读 · 1 评论 -
13-TCP 协议(FIN_WAIT2)
1. FIN_WAIT_2 状态如果你完成了上一篇文章的实验,你肯定见过了 FIN_WAIT2 状态。当主动关闭一方进入 FIN_WAIT2 状态时,只要对端还没有发送 FIN 段过来(处于 CLOSE_WAIT 状态,等等再关闭,我还有数据要发送),就会一直停留在这个状态。因此,FIN_WAIT2 状态会非常容易见到。 图1 处于 FIN_WAIT2 状态 很不幸,主动关闭一方有可能永远处原创 2017-04-08 18:15:03 · 2505 阅读 · 0 评论 -
4-TCP 协议(抓包)
既然我们要分析 TCP(Transmision Control Protocol) 协议,首先我们得先抓个包看看,再进行分析。1. 准备工作为了能够控制网络数据的传输,我们自己写一个简单的 TCP 协议的程序。我相信这一块你已经非常熟练了,在Linux 编程学习笔记的第十四部分,我们已经对简单的 socket 编程基础做了一个介绍。在这个部分,我们需要利用之前我们写好的基于 TCP 协议的大写转换服原创 2017-04-05 11:35:36 · 4675 阅读 · 4 评论 -
15-TCP 协议(半打开)
1. 半打开(Half-Open) 如果一方已经关闭或异常终止,而另一方却对此毫不知情,这种连接就称为半打开的。比如:其中一端突然断网了,或者停电导致的异常关机。假设在主机 A 和 B 之间建立了一条 TCP 连接,由于停电导致主机 B 异常关机。接下来,我们分三种情况讨论,A 此时继续给 B 发数据,会有什么现象。B 仍然关机B 开机,但是未启动服务B 开机并重新启动了服务2. 实验原创 2017-04-10 14:59:08 · 3776 阅读 · 1 评论 -
16-TCP 协议(同时关闭)
有同学会问,为什么不写同时打开?(同时打开指的是两端都是服务器,两端同时向对方建立连接请求)。一方面,在我们实际生活中几乎遇不到;另一方面,很多操作系统实际都不能正确的支持同时打开,所以,这里就不写了,如果你对这个很感兴趣,请参考《TCP/IP 详解卷1:协议》的 18.8 小节。1. 同时关闭 同时关闭,指的是已建立连接的两端同时发起主动关闭。TCP 协议允许这种事情发生。见图 1.原创 2017-04-10 15:44:30 · 2918 阅读 · 0 评论 -
18-TCP 协议(迟到的 ACK—— Linux)
在上一篇文章中已经分析了 windows 在回复确认时的情况,在接收到 TCP 段的情况下,等待 200ms 再回复 ack,除非在这 200ms 里接收方也有数据要发给对方,于是就在发送数据的时候将 ack 捎带过去。本文我们分析 Linux 中的情况,我使用的是 Unbutu 14.4.1. 实验1.1 实验步骤服务器 unp/protocol/tools/winserver/tcp_ser原创 2017-04-11 12:59:20 · 2732 阅读 · 3 评论 -
19- TCP 协议(Nagle)
前面我们所用的 unp/protocol/tools/winclient/echo_cli.cpp 程序的特别之处是它总会发送一个小分组(TCP 段,只有 41 字节)到服务器。这样的小分组在英文中称为 tinygram,在网络状态好的情况下,比如局域网中,通常不会引起什么麻烦。但是在广域网中,这样的小分组会增加网络拥塞的可能。为了能够减少这样的 tinygram 在网络中的数量,在 TCP 协议栈原创 2017-04-11 14:50:31 · 2356 阅读 · 0 评论 -
20-TCP 协议(滑动窗口——基础)
相信大家都遇到过这样的场景: 同学 Luffy 给你打电话,让你记下一串手机号码,可是你记忆力不太好,你跟 Luffy 约定,一次只最多只能报 4 个数字,Luffy 念一遍,如果你听到了就把他说的话重复一遍。接下来: 你:你一次最多报 4 个数字,多了我记不住啊! Luffy:139 你:139 (Luffy 知道你听到了) Luffy:7548 你:75...原创 2017-04-12 14:46:47 · 5978 阅读 · 1 评论 -
21-TCP 协议(滑动窗口——抓包分析)
在上一文中我们已经介绍了滑动窗口的基本概念,以及它的目的。本文我们就亲自动手实践一下。1. 环境准备git 地址:https://git.oschina.net/ivan_allen/unp.git服务器:unp/protocol/tools/tcpserver/sink_serv.c,部署在 Linux 上。客户端:/home/allen/unp/protocol/tools/winclien原创 2017-04-12 15:18:40 · 5522 阅读 · 1 评论 -
3-第一次抓包
咱们先来简单的熟悉一下怎么用 OmniPeek 来抓包。前提你得先安装好啊……1. 抓取数据包当你首次打开界面的时候是这样的: 图1 OmniPeek 启动界面 接下来,点按钮 New Capture。会弹出下面这个框框: 图2 新建一个工程 点击 Adapter,这个选项表示你想抓哪个网卡上的数据帧: 图3 选一个你正在上网的网卡 选好网卡后,直接确认就行了。接下来出现这个原创 2017-04-05 10:24:03 · 2675 阅读 · 0 评论 -
5-TCP 协议(基础)
1. TCP 协议是什么前面一直在嚷嚷 TCP 协议,却一直不知道它到底是个什么东西。用举例来说明:你和你对象(没有对象那就选你上铺或下铺的同学吧)发短信,事先约定,你给他发送任何短信,TA 都得回复你一句:收到。我想这个在你平时生活中应该有所遇到。比如你发送“早安”给 TA,TA 会回复你:“收到”。如果过了 1 分钟你还没有收到 TA 的回复(也许是你发送的短信 TA 没收到,也许是 TA 已经原创 2017-04-05 13:51:23 · 3030 阅读 · 0 评论 -
22-TCP 协议(PSH 标志)
1. PSH 标志位从你第一次抓包以来,PSH 标志位几乎与你形影不离。它的英文单词是 PUSH,表示“推”的意思。1.1 接收缓冲区和发送缓冲区在谈 PSH 标志位前,先来说说 TCP 双方是如何发送数据的。假设有发送方 A 和接收方 B。发送方有一个发送缓冲区,接收方有一个接收缓冲区,见图 1。进程 A 发送”hello”, “world” 后,只是将这些数据写到自己的发送缓冲区,为了能讲清 P原创 2017-04-13 11:13:23 · 48158 阅读 · 9 评论 -
32-网络编程概述
1. 预备知识从网络编程开始(基于 socket 套接字的编程),我们要用到很多很多在Linux 环境编程中学到的知识,比较典型的就是信号处理,多进程,多线程这些知识。如果你对这些东西感觉还是很模糊,后面学习起来会相当困难。我并不打算把这些知识在网络编程中重复,所以如果你对这些知识感觉很困惑,请跳到《Linux环境编程学习笔记》中学习。另一方面,有关基本的网络编程基础,在《Linux环境编程学习笔记原创 2017-04-19 13:53:48 · 1782 阅读 · 0 评论 -
9-TCP 协议(连接异常)
有很多情况导致连接无法建立。本文我们分析 2 种情况,分别是针对 Windows 和 Linux 进行讨论,它们是有区别的。第一种情况是连接的主机不在网络中第二种情况是主机在网络中,但是对应的服务未开启不同版本的 Linux 内核也是有区别的。这里我使用的是 Ubuntu 14.04 LTS 版本。1. 相关网络地址对应关系在这里牵扯的 ip 地址有点多,可能会让你乱...原创 2017-04-06 16:46:11 · 2615 阅读 · 4 评论 -
23-TCP 协议(紧急标志)
1. 紧急标志当你再次看到图 1 时,相信你已经无比的亲切,再观察下面彩色的 6 个标志位,有 5 个你已经熟知了,还剩下最后一个 URG,对,就是图 1 中那个鲜红的,醒目的那个位置。 图1 TCP 首部 除此之外,还有一个字段—— 16 位紧急指针,它正是配合 URG 标志位一起使用的,言外之意就是这个字段只有在 URG 被置位时才有意义。因为只有一个紧急指针,这也意味着它只能标识一个字原创 2017-04-19 17:29:00 · 9800 阅读 · 3 评论 -
31-TCP 协议(保活定时器)
1. Keep AliveTCP 保活定时器,Keep Alive,特别强调一下,不是 HTTP 协议里的那个 Keep Alive.在 HTTP 中,keep alive 是在应用层实现的,目的在于延长连接时间,即应用层服务器如果在一定时间内(通过 keep alive 进行设置)没有和客户端交互,就关闭连接。感兴趣的朋友可以自行 baidu or google.TCP 中的 Keepalive原创 2017-04-16 18:00:36 · 2265 阅读 · 0 评论 -
30-TCP 协议(糊涂窗口综合症)
1. 糊涂窗口综合症糊涂窗口综合症,这个名字很有意思,原文叫 Silly Window Syndrome,简称 SWS.一看到窗口,我们就应该反应过来这是流量控制中的东西。SWS 是这样一种情况:接收方通告了一个 1 字节的窗口给发送方,然后发送方发送了 1 字节的数据给接收方。接着,接收方又通告了一个 1 字节的窗口,这样持续下去,使网络的效率很低。2. 解决 SWS有两种办法可以解决此问题:针原创 2017-04-16 17:42:39 · 2347 阅读 · 0 评论 -
29-TCP 协议(持续定时器)
1. 持续定时器在我们学习滑动窗口协议的时,遇到过窗口大小为 0 的情况。接收方通告一个 0 窗口给接收方,可以用来阻止发送方继续发送数据。如果在某个时候,接收方缓冲区有空间了,于是发送了一个非 0 窗口的通告给接收方,不幸的是这个通告丢失了,而发送方却还在死等接收方的非 0 窗口通告,接下来就成了死锁。为了防止这种情况,发送方只要接收到了 0 窗口通告,就开启一个持续定时器(persist tim原创 2017-04-16 17:20:17 · 1776 阅读 · 0 评论 -
26-TCP 协议(慢启动与拥塞避免)
观察到上一个实验中的慢启动的现象后,接下来我们就详细讲讲到底是怎么一回事。1. 慢启动算法对于发送方来说,TCP 维护了一个变量 cwnd (congestion window),这个变量称为拥塞窗口,它的大小就是 cwnd。它表示发送方一次想要发送多少字节的数据。cwnd 是一个动态变化的值,它会根据网络的情况实时的调整自己,最后,cwnd 就会适应网络的情况,以保证发送 cwnd 字节的数据而网原创 2017-04-14 19:48:59 · 2955 阅读 · 5 评论 -
25-TCP 协议(慢启动——观察)
在上一节,我们已经介绍了网络拥塞以及常用的拥塞控制算法,另外,我们还简单的讲述了如何试探性的去探测网络有没有拥塞。实际上,慢启动算法也是这样做的,只是比这个稍稍复杂一点。在讲慢启动算法之前, 我们先做一个实验,观察一下。1. 实验环境服务器 unp/protocol/tools/tcpserver/psh_serv.c,部署在 Linux 上。客户端 unp/protocol/tools/win原创 2017-04-14 15:17:08 · 2234 阅读 · 0 评论 -
24-TCP 协议(拥塞控制)
1.概述在学习拥塞控制前,我们假设:接收方总是有足够大的缓存空间,接收方的接收窗口大小总是很大——这意味着接收方对数据来者不拒。在基于这样的理想条件上,如果发送方发送的数据接收方没有收到,那么大抵上可以判断为网络出现了拥塞。2. 网络拥塞是怎么来的 图1 某个小型局域网 图 1 所示的是一个典型的小型局域网,SW 表示交换机,R 表示路由器。基于第 1 节中所述的假设,如果 PC1 给主机原创 2017-04-14 13:20:04 · 1654 阅读 · 4 评论 -
33-基于 TCP 的回射服务器
有些同学可能没有完成上一节留下的任务。所以,还是有必要在浏览一下整个程序的结构,不然大家可能看看文章也就过去了。如果你还没有 git clone,赶紧的把下面命令输入到你的机器中执行。https://git.oschina.net/ivan_allen/unp.git1. 文件浏览 图1 相关文件 目前在 unp/program 下,有一个 echo (回射服务器)文件夹,它下面存的全是不同原创 2017-04-19 20:01:02 · 1852 阅读 · 1 评论 -
65-高级 I/O 函数与技术
UDP 的基础内容已经结束,但是 UDP 远远不止于此,后面还会有更多关于 UDP 更多的讨论。不过在此之前,我们还得学习更多更高级的网络编程知识。很久以前学习 Linux 环境编程时,也写过高级 I/O 相关的笔记,那时候主要讨论了三大块内容:记录锁、IO 多路复用和异步 IO. 这一次要网络编程中,我们要学习的高级 I/O 当然只是针对网络编程来说的,这次的内容包含函数和编程技巧的讲解:为 I原创 2017-05-02 08:57:34 · 916 阅读 · 1 评论 -
66-套接字超时(alarm)
我们知道,使用 read 或 recvfrom 函数从 socket 上读取数据时,可能会导致阻塞。特别是 UDP 服务器,稍有不甚,数据报就丢失就会直接导致程序假死(阻塞在 recvfrom)。还有 connect 函数,如果去连接一个网络上不存在的主机,需要等待很长时间,可能长达 2 分钟。如果我们能控制它在指定的时间内连接不上,就直接报错,行不行呢?很可惜,上面的问题 linux 并未直接提供原创 2017-05-02 09:47:28 · 1213 阅读 · 1 评论 -
67-套接字超时(select)
设置超时的第二个技术是使用 select 函数。它使用了 select 函数的最后一个超时参数,对套接字描述符进行了“预读”。1. 程序路径代码托管在 gitos 上,请使用下面的命令获取:git clone https://git.oschina.net/ivan_allen/unp.git如果你已经 clone 过这个代码了,请使用 Git pull 更新一下。本节程序所使用的程序路径是 unp原创 2017-05-02 10:06:09 · 1139 阅读 · 1 评论 -
68-套接字超时(SO_RCVTIMEO 与 SO_SNDTIMEO)
设置套接字超时的第三个技术是使用套接字选项 SO_RCVTIMEO 与 SO_SNDTIMEO,它的优势在于一次设置,所有应用于该套接字的操作都自动带有超时时间。它就好像是一个全局开关。比如对于 SO_RCVTIMEO 来说,如果设置了它,所有对该套接字的读操作在规定的时间里没完成,就直接返回并设置 errno = EWOULDBLOCK,对于 SO_SNDTIMEO 选项来说也是一样。1. 程序路原创 2017-05-02 10:22:23 · 17317 阅读 · 2 评论 -
69-recv 和 send 函数
recv 和 send 函数专门用于套接字描述符的,相比于 read 和 write,前三个参数一模一样。recv 和 send 只多了一个参数 —— flags.如果你还记得 recvfrom 和 sendto,你应该能回忆起它们也有一个参数 flags,那时候没有讲解这个标志位,是因为放到这篇文章一起讲了。1. recv 和 send函数原型 ssize_t recv(int sockfd原创 2017-05-02 10:45:03 · 1266 阅读 · 1 评论 -
70-散布读、聚集写
看到这个标题你可能会懵圈,没事,只是名字有点恐怖而已。在英文中,它们被称为 scatter read和 gather write.1. 引例看下面一段代码:char buf1[10];char buf2[20];char buf3[15];write(fd, buf1, 10);write(fd, buf2, 20);write(fd, buf3, 15);上面这样的代码实际上很常见,不知道原创 2017-05-02 13:31:28 · 1094 阅读 · 1 评论 -
71-recvmsg 和 sendmsg 函数
这两个函数只适用于套接字描述符。read、readv、recv 和 recvfrom 能用的地方,recvmsg 都能使用,而且,recvmsg 能提供更多的功能。同样的,各种 output 类型的函数都可以替换成 sendmsg 函数。所以,recvmsg 和 sendmsg 是之前我们学过的读写类函数的究极形态。这么强大的函数,使用起来也会相当的复杂,在本文,我们只讨论它的一部分功能,剩下的功能原创 2017-05-02 17:39:08 · 2293 阅读 · 7 评论 -
72-套接字与标准I/O
之前我们使用 read,write 及其他们的变体(recv, send) 函数读写 I/O,这些函数都是围绕着描述符工作的。我们将这一类 I/O 称为 Unix I/O.我们也可以使用标准 I/O 函数库来读写 I/O,它由 ANSI C 标准进行规范,比如 fputs, fgets 等等。当然了,fputs, fgets 这一类函数也可以用于套接字,不过这需要从描述符创建一个标准 I/O 流,主原创 2017-05-02 19:50:55 · 917 阅读 · 1 评论 -
35-并发服务器(多进程)
待你进一步完善了前面的 echo 服务器后,也处理了对端发送而来的 RST 段而导致的错误。现在,我们遇到了一个新问题,即客户端在关闭退出后,服务器也关闭退出了。1. 让服务器永远运行解决的办法很简单,我们将 server 改进为下面这样:void server_routine() { // bind, listen while(1) { sockfd = accept(li原创 2017-04-20 17:08:11 · 1599 阅读 · 1 评论 -
36-多进程并发服务器(僵尸进程与信号处理)
在上一篇文章中,最后遗留了一个僵尸进程的问题。一旦客户端关闭连接,服务器子进程就会退出,然而父进程仍然存在,就产生了“白发人送黑发人”的场景。如果父进程没有主动回收(wait)子进程,或者没有忽略 SIGCHLD 信号,退出的子进程就会成为僵尸进程。代码托管在 gitos 上,请使用下面的命令获取:git clone https://git.oschina.net/ivan_allen/unp.gi原创 2017-04-21 09:59:53 · 1927 阅读 · 0 评论 -
37-多进程并发服务器(并发测试)
因为我们没有大量的测试机器,所以只能在单机上模拟大量客户端去连接服务器。代码托管在 gitos 上,请使用下面的命令获取:git clone https://git.oschina.net/ivan_allen/unp.git如果你已经 clone 过这个代码了,请使用 git pull 更新一下。1. 客户端与服务器程序客户端本文所使用的客户端程序路径是:unp/program/concurr原创 2017-04-21 13:36:38 · 2143 阅读 · 1 评论 -
87-非阻塞 connect
非阻塞i/o 上调用 connect 比非阻塞 i/o 上调用 read/write 要麻烦一点,一方面 connect 函数不能像 read/write 那样反复调用,它只能调用一次;另一方面,connect 函数返回错误,并不代表连接建立不成功。1. 非阻塞 connect对于 TCP 协议,在非阻塞 i/o 上调用 connect,意味着 connect 会发送 SYN 段给服务...原创 2017-05-12 10:33:18 · 1161 阅读 · 5 评论 -
86-时间获取客户端
本文来一点比较轻松的话题,来写一个客户端,从时间服务器(daytime server) 上取得时间并打印。1. daytime 服务器daytime 服务器我们不用自己写了,这个网站列举了很多现成的 daytime 服务器地址:http://tf.nist.gov/tf-cgi/servers.cgi , 剩下的事情我们就只管写客户端。daytime 服务器使用的是 TCP 协议,默认端口是 13。原创 2017-05-10 12:40:36 · 1312 阅读 · 2 评论 -
73-进程间传递描述符(概述)
从这一篇开始,正式进入 Unix Domain Protocols —— Unix 域协议。不过本文标题似乎与 Unix 域协议没有什么关系,实际上,它是 unix 域协议的一个应用。接下来,我们进入主题。1. 如何在进程间传递描述符早先在 Linux 环境编程中学习 fork 函数的时候,我们就知道子进程可以继承父进程所有打开的描述符,很明显,这是一种传递描述符的方式。int fd = open(原创 2017-05-04 14:25:14 · 898 阅读 · 1 评论 -
74-Unix 域套接字地址结构
1. unix 域协议简介不同于 ipv4 的 AF_INET,unix 域只用于本机进程间通信,它所使用的完全是另一套协议。在使用 unix 域的时候,socket 函数的第一个参数必须指定为 AF_LOCAL 或者 AF_UNIX,表示创建一个 unix 域套接字。2. sockaddr_un {}不同于 ipv4 的 sockaddr_in{} 结构,unix 域的套接字地址结构为 socka原创 2017-05-04 16:44:49 · 1195 阅读 · 1 评论