![](https://img-blog.csdnimg.cn/20190213160951788.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
网络编程学习
这里主要总结了我在学习unix网络编程的时侯积累的知识以及心得. 其中大部分的内容来至UNIX网络编程和计算机网络第七版(谢希仁)
Function_18
这个作者很懒,什么都没留下…
展开
-
0. 网络编程目录
至今已经在第二次写网络编程的博客了, 去年将网络分析和系统编程一起进行整理的, 而且没有对每一个知识点进行归纳和总结. 前段时间还是又回顾了TCP编程的一点基础, 为了以后回顾还有学习网络编程的看到写的博客后能够成系列的来学习, 还是决定还是重新整理一下更好.现在模块分为四个部分 : TCP通信, TCP协议(计算机网络的部分知识), UDP通信, HTTP 通信.整个板块的目的就在于如何实...原创 2019-05-16 12:23:32 · 668 阅读 · 0 评论 -
53. 线程池
一般在web服务端使用线程池是比较常见的, 本节呢, 就已以实现一个简单的web服务端为目标, 仅仅实现GET请求, 最多在加上POST请求.如果对web服务端并不熟悉的, 可以回过头去看一下http请求与应答以及一个500行左右的web服务端源码tinyhttpd(整理了源码以及修改和加注释后的linux版本).线程池主要函数线程池完整代码位置 : threadpool因为线程池的...原创 2019-05-10 15:19:54 · 385 阅读 · 2 评论 -
52. 线程-IO复用(EPOLLONESHOT)
线程怎么与IO复用联系起来, IO复用中创建线程? 还是线程中IO复用? 这个问题用在进程也是一样的. 其实两种方式都可以. 本节采用在 IO复用中创建线程, 接下来就来看看具体怎么实现的吧.epoll 的EPOLLONESHOT事件还记得 epoll 的 event 可设置的状态吗? 忘了也不急, 这里将 IO复用之epoll函数 的状态粘贴过来.event值描述...原创 2019-05-10 15:17:54 · 372 阅读 · 0 评论 -
51. 线程-服务端
在最开始实现并发服务端的时候, 最开始想到的办法便是使用多进程, 使每个 TCP 连接对应一个进程; 之后我们又将多进程并发改写成了 IO 复用的方式实现了相同的功能; 但现在唯一没有将服务端改写成线程, 本节就来改写服务端.线程服务端在改写成多线程之前, 要对 [线程创建], [线程同步]以及线程终止有所了解才行.主函数仅仅只是将连接后回射操作交给线程即可 :int main(in...原创 2019-05-10 15:14:41 · 273 阅读 · 0 评论 -
50. 进程池
一般进程池和线程池都是并发编程中常见的, 如nginx采用进程池, 也有实现协程降低上下文切换的代价等等, 使用和实现这些方法都是为了提高我们服务端的并发能力.进程池和线程池都是避免服务端频繁的创建进程(线程), 毕竟创建进程(线程)的代价很大. 所以可先在程序运行时便分配出一定的进程(线程)数, 如果有事件就绪便可以直接调用分配好的进程, 让进程池中的进程区处理事件, 事件处理结束后进...原创 2019-05-10 15:12:31 · 286 阅读 · 0 评论 -
49. HTTP 请求/应答
HTTP 协议是 Hyper Text Transfer Protocol (超文本传输协议) 缩写, 并且是基于 TCP/IP 通信协议来传递数据.HTTP 协议特点无连接 : 每次进行一次 HTTP 通信. 服务器处理完客户的请求并收到客户的应答后立即断开连接, 这种方式被称为短连接. 采用这种方式可以节省传输时间, 但是连续传输使用短连接就比较消耗资源. (http1.1后有长连...原创 2019-05-10 15:10:16 · 2835 阅读 · 0 评论 -
48. 半同步/半异步
本节说到的半同步与半异步跟同步和异步并不是一个概念, 请不要混淆了. 也为了避免混淆, 下面也会对同步和异步做一个简要的说明.同步/异步同步和异步是属于IO模型中, 前面已经对IO模型有过接触了( 如 非阻塞IO[1]).同步 : 内核通知进程有数据到来, 进程从内核空间中将数据复制到应用空间中.异步 : 内核将数据复制到指定的空间中后通知进程, 进程只管处理数据. 异步不会阻塞....原创 2019-05-10 15:08:57 · 888 阅读 · 0 评论 -
47. web 客户程序
前面铺垫了非阻塞 connect 以及 HTTP 请求, 本节就已 unp 书上的例子实现一个简单的 web 客户端程序.客户程序使用非阻塞式connect 保证同时能建立多个 TCP 连接.如果使用阻塞式 connect, 每次都必须等待上一个连接成功后才能建立下一个连接; 而我们所写的客户程序只是将第一个连接单独执行, 之后的多个连接再并行连接.完整代码 : client_web...原创 2019-05-10 15:07:27 · 359 阅读 · 0 评论 -
46. 域名解析
前面我们使用的所有客户端建立连接都是在知道对方的 IP 地址基础上进行的. 但是如果我们需要使用前面的客户端程序与网页建立连接难不成还要记住该网页的 IP 不成?当然. 有过网络基础上肯定知道 DNS域名服务器. 该类域名系统通过主机名就可以查询得到其 IP 地址, 之后便顺利进行连接. 当然操作系统也为我们提供这类系统函数, 保证我们只需要通过主机名就能与网页发起连接.gethostna...原创 2019-05-10 15:05:10 · 348 阅读 · 0 评论 -
45. connect 实现定时
我们需要先连接 getaddrinfo, 而 getaddrinfo 的特性实在太多, 本节也仅仅只是简单的做一个小结, 如果想要了解更加全面可以参考 unp 第245页.getaddrinfo 函数getaddrinfo 函数是与协议无关 (TCP, UDP都可以) 并且不仅支持 IPV4 还支持 IPV6 .函数原型 :#include <netdb.h>int g...原创 2019-05-08 16:26:29 · 338 阅读 · 0 评论 -
44. 最大保持TCP连接个数
前面通过IO复用实现了 connect 的定时, 本节使用 connect 非阻塞验证进程 能保持多少 TCP连接.非阻塞式非阻塞 connect 还能用来测试服务端的抗压能力, 当然使用阻塞 connect 也能够保持多个 TCP 连接, 但效率没有非阻塞高. 可以看出来同一时间阻塞式的必须保证一个连接成功才会执行后一个连接, 非阻塞式能够在同一时间保证多个连接的进行.完整代码 : ...原创 2019-05-08 16:23:56 · 639 阅读 · 0 评论 -
43. TCP套接字之connect非阻塞
本节来将客户端的connect阻塞式改为非阻塞式. 这样可以同时向服务端发起多个连接并一起进行处理, 非阻塞connect一般用来测试服务端的抗压能力.connect 非阻塞用途connect设置为非阻塞之后会立即返回 设置errno为 EINPROGRESS 错误, 表示连接操作正在进行中, 但是仍未完成连接; 同时TCP的三次握手操作继续进行. 之后, 可以调用 select 来检查...原创 2019-05-08 16:21:32 · 908 阅读 · 0 评论 -
42. TCP套接字之accept非阻塞
本节来理论性的了解一下关于服务端 accept 非阻塞.阻塞 accept服务器在繁忙过程时, 在建立三次握手之后, 调用accept之前, 如果出现客户端突然断开连接的情况, POSIX 指出这种情况 errno 设置为 CONNABORTED.如: 三次握手之后, 客户端发送 RST后断开连接, 之后服务端调用accept准备执行连接但并不知道对端已经关闭, 这个时候accept就...原创 2019-05-08 16:20:14 · 2777 阅读 · 0 评论 -
41. 非阻塞IO
前面我们所使用的IO都是阻塞式的, 当然, 默认也是阻塞式的. 不过我们也可以设置文件描述符将阻塞式变为非阻塞式. 我们为什么会将阻塞式转为非阻塞式呢? 肯定是有好处的, 而本节就先简单介绍一下关于非阻塞式.阻塞式先来了解一下阻塞式.阻塞式 : 进程运行到阻塞式的函数时会被投入睡眠切换执行其他程序, 直到被中断或者被唤醒才会切换回程序继续执行.阻塞式的问题 :对于CPU来说IO操作...原创 2019-05-08 16:18:21 · 523 阅读 · 0 评论 -
40. socket 就绪条件
在实现网络通信前, 先来了解一下socket套接字什么时候就绪(可读可写). 第一次学习socket只需要明白我用红色标记的条件就行.缓冲区每个套接字接收区缓存 (用于读) 和发送区缓存 (用于写) :接收区缓存: 接收数据, 从内核缓冲复制到用户应用程序数据缓冲区.发送去缓存: 用户应用程序数据缓冲区复制到内核缓冲区, 等待发送.每个套接字都有接收缓存区低水位标记(用于读)和...原创 2019-05-08 13:04:59 · 352 阅读 · 0 评论 -
39. TCP套接字之日志记录
前面我们实现了完整的TCP通信, 现在我们可以来考虑为通信加上日志记录的功能. 实现日志记录可以直接将数据写入文件中.管道实现日志记录这里采用管道实现进程间通信, 通过一个单独的进程来记录日志.主要用到的就是文件的创建, 无名管道以及进程间通信的方法.以下是删除了大部分的服务端代码, 只留下了修改过后的代码. 这里采用的是带缓冲的fwrite函数实现向文件里写入数据. 因为采用的fw...原创 2019-05-08 12:57:20 · 764 阅读 · 0 评论 -
38. TCP套接字之标准IO
上节实验了关于标准IO能够明显提升运行效率, 那么本节就来将之前使用的系统IO改为标准IO试试.修改为标准IO本节修改的代码是epoll中修改后的代码. 其实就只需要把客服端的read函数换成标准IO的fgets即可.while(1){ testrfds = rfds; select(sockfd + 1, &testrfds, NULL, NULL, NULL); if(...原创 2019-05-08 12:54:46 · 283 阅读 · 0 评论 -
36. UDP套接字之有连接通信
上一节最后发现服务端不存在客服端并不知道, 会被一直阻塞.错误回顾如果你忘了启动服务端, 你会发现客服端依旧被阻塞了, 并且没有报错. 而且发送数据即使没有收到应答的数据也没有报错, 程序仍然处于阻塞状态.错误解析其实在客服端与服务端主机发送UDP数据报之前, 需要一次arp请求和应答交换(我是在一个主机上实验, 所以无法抓取到).我们在通过抓包可以看到,服务端会响应一个port...原创 2019-05-08 12:48:10 · 432 阅读 · 0 评论 -
37. 标准IO
前面我们使用所有的输入输出都是无缓冲的系统IO, 那么能不能用标准IO来代替系统IO呢?可能有人回想问为什么要代替系统IO呢? 先来看一个例子就知道原因了.复制文件这里我使用系统IO和标准IO来复制一个比较大的文件来说明原因. 这里实验的文件大小是200M左右系统IO :完整代码 : stdcpy.c#include <stdio.h>#include <un...原创 2019-05-08 12:51:40 · 236 阅读 · 0 评论 -
35. UDP套接字之无连接通信
如同TCP通信一样, UDP套接字也有专门的发送和接收数据的函数对应. TCP是recv和send两个函数负责收发, UDP是通过recvfrom和sendto两个函数负责收发数据.recvfrom和sendto函数函数原型:#include <sys/socket.h>ssize_t recvform(int sockfd, void *buff, size_t nb...原创 2019-05-07 10:04:16 · 429 阅读 · 0 评论 -
34. UDP协议
接下来准备简单探讨一下关于UDP套接字编程.UDP头部UDP是面向报文.UDP的头部是固定8字节, 分别是 : 源端口, 目的端口, 长度, 检验和.校验和是用来保证数据的安全.UDP协议UDP是一种无连接的传输层协议, 提供面向事务的简单不可靠信息传送服务, 适合于一次传输少量数据; 在网络环境较差的情况下, UDP协议数据包丢失会比较严重.不可靠 :不提供报文到达确认...原创 2019-05-07 10:00:44 · 420 阅读 · 0 评论 -
30.TCP协议之TCP缓冲区
每个套接字都会有一个发送缓冲区和接收缓冲区, 这样的功能保证了TCP的容错性, 毕竟数据有保存可以重传.TCP缓冲区对TCP来说套接字接收缓冲区限制了TCP通告对端的窗口大小. 并且, 接收缓冲区不存在溢出问题, 因为不允许发送超过本端所通告窗口大小的数据, 这就是TCP流量控制. 如果对端发送了超过窗口大小的数据, 则接收端将直接丢弃.UDP缓冲区既然说了TCP缓冲区, 顺便提一...原创 2019-05-07 09:56:36 · 2784 阅读 · 1 评论 -
29. 套接字选项之SO_REUSEADDR
在TCP四次挥手中有time_wait状态, 该状态使得进入该状态的端口在2MSL的时间内不能再次被绑定, 这对客服端并没有太大的影响, 这个对服务端的影响就很大了. 一般我们编写的服务端连接都很少, 而高并发服务器对于端口立即绑定是必须的, 毕竟服务端也可能掉线而等上2MSL的时间肯定不允许.SO_REUSEADDR 选项允许绑定处于 TIME_WAIT 状态的套接字地址允许在...原创 2019-05-07 09:55:04 · 347 阅读 · 0 评论 -
26. TCP协议之紧急模式
前面我们分析过TCP的ACK, RST等, 本节来分析URG.TCP报文段首部格式注意 : TCP虽然是面向字节流的, 但是TCP传送的数据单元却是报文段.消息被设置为紧急时会把TCP状态标记为URG, 同时还会设置紧急指针.紧急模式在套接字选项中找不到关于URG的描述, 那么该消息又怎样被标记为紧急呢? 别急, 消息标记为紧急数据这个在最开始实现套接字通信中有说到过. 紧急标...原创 2019-05-07 09:51:58 · 842 阅读 · 0 评论 -
20. 从编程方面分析三次握手过程
前面分析过了理论的三次握手的过程以及为什么需要三次握手, 本节我们再以socket编程的方面分析三次握手的过程.从编程角度分析三次握手三次握手, 三个函数, 分别是listen, connect和accept.服务端调用listen函数一直监听网络中有没有要与服务端连接的客户端, 并且**listen初始化未决连接队列**.未决连接队列分为未完成连接队列和已完成连接队列, 这里是我...原创 2019-05-07 09:48:44 · 673 阅读 · 0 评论 -
18. TCP/IP协议族
TCP/IP协议族不像理论的协议关系有7层, 前者只有四层. 自底而下分别是 : 数据链路层, 网络层, 传输层, 应用层; 每一层对应不同的功能. 本节只是简单的介绍一下关于这四层协议的功能.数据链路层数据链路层实现了网卡接口的网络驱动程序, 以处理数据在物理媒介(以太网等)上的传输过程.数据链路层常用的是连个协议 : ARP协议和RARP协议.网络通信看上去是上层之间的直接通...原创 2019-05-07 09:44:13 · 348 阅读 · 0 评论 -
14. TCP套接字之shutdown函数
前面我们虽然解决了困惑我们很久客服端的问题, 但是虽然解决了但是该客服端还有更加大的隐患存在, 接下来我们就来看一下问题所在和问题解决办法.问题浮现使用前面IO复用之select 的客服端和服务端都改写成的完整代码做实验.完整代码 : select_server_client.c服务端运行: ./a.out 1 8080 127.0.0.1客服端运行:./a.out 2 808...原创 2019-05-07 09:38:40 · 1040 阅读 · 0 评论 -
12 TCP套接字之IO分离
前面通过信号捕捉也没有完美的解决客服端阻塞的问题, 那么本节我们通过将客服端的IO操作分离的办法来解决这个困惑我们很久的bug吧.IO分离第一次听到 IO分离 肯定会感觉很陌生, 不急, 下面我会解释的.IO分离实际是将 read逻辑操作(也就是读操作) 和 write逻辑操作(也就是写操作) 的实现分离开. 分离技术有多种, 本节也仅仅介绍一种简单.疑惑在SIGPIPE信号中我们...原创 2019-05-07 09:08:55 · 447 阅读 · 0 评论 -
11 TCP套接字之SIGPIPE信号
前面我们解决了并发服务端的问题, 但是还是没有解决掉客服端的bug.问题重现我们以上一节的代码为例浮现这个bug.完整代码 : fork_SIGCHLD.c可能你已经忘了客服端的问题了, 这里在重新说明一下 : 当建立连接后, 服务端主动关闭后, 客服端并没有立即退出, 而是处于阻塞状态直到有输入才会退出.问题分析分析问题的时, 应该先来看一下抓包的情况.问题基本也能分析出...原创 2019-05-07 09:02:11 · 692 阅读 · 0 评论 -
进程最大打开文件描述符个数
不过在看下节之前, 首先知道在本机下打开的文件描述符个数的个数不能超过 1024, 除去3个输入输出还有epoll的文件描述符, 所以程序传入的最大打开文件描述符的参数不能超过 1020. 如果超过服务端报错结果如下 :临时最大进程最大打开文件描述符通过查看一个进程的最多打开个数, ulimit -n设置临时设置打开个数 :limit -n10001在普通用户下最多能够临时打...原创 2019-05-06 23:26:31 · 4072 阅读 · 0 评论 -
17. IO复用之epoll触发模式
epoll有两种触发模式 : 水平触发和边沿触发. 默认为水平触发模式.水平触发什么叫做水平触发呢? IO大都有缓冲区, 当缓冲区里面只要有数据时就会触发水平模式,直到将缓冲的数据读写结束才不会触发水平模式.举个栗子 : 当我们现在的读缓冲区有1024字节的数据而我们每次都只能读一个字节, 那么一次读操作后缓冲区还有1023字节, 此时又继续触发水平模式继续读, 直到1024字节读完才不会触...原创 2019-03-09 11:28:59 · 526 阅读 · 0 评论 -
16.IO复用之epoll函数
前面介绍了select函数和poll函数, select我们知道能够支持的套接字个数太少了, 但是poll函数已经很好了也没有什么缺点啊为啥还要介绍epoll呢? 接下来我们就来谈谈poll和select函数的其他问题.poll和select的问题poll函数一般使用都是将它设置为轮询的方式, 这样是很占用CPU的; 当然可以将其设置为阻塞也就能避免这个问题.select能够监听的描...原创 2019-03-09 11:27:36 · 462 阅读 · 0 评论 -
15. IO复用之poll函数
前面介绍了使用select函数能避免服务端关闭而客户端还在阻塞的问题, 同时也能将多进程的服务端改写成单进程就能完成多个客服端的连接. 但是使用select代替多进程服务端还有很大的问题, 比如fd_set只能支持1024个文件描述符, 对于服务器太少了.本节介绍另一个IO多路复用函数来弥补select的个别不足.函数原型poll 一次能够监听的描述符个数是根据数组大小来决定的, 最大值远大...原创 2019-03-09 11:26:48 · 519 阅读 · 0 评论 -
13 IO复用之select函数
前面我们所有的代码都是通过read和write操作, 每次只能处理一个IO请求. 但是IO复用可以在同时处理多个socket的IO请求. 而且IO复用与线程连用是最常见的搭配.本节介绍IO多路复用select函数.函数原型#include <sys/types.h>#include <sys/times.h>#include <sys/select.h>...原创 2019-03-09 11:25:16 · 786 阅读 · 0 评论 -
33.TCP异常之服务器中断
在前面TCP套接字通信中有一个关于服务端关闭但是客户端没有断开的问题, 这个问题一直没有得到解决, 本篇就来分析为什么会出现这样的情况, 而又怎么解决.问题重现这个问题的重现可以使用TCP套接字之通信中的代码, 也可以用TCP套接字之SIGCHLD中的代码. 这里我就使用后者.服务端运行 :./a.out 1 8080 192.168.1.16客户端运行 :./a.out 2 808...原创 2019-03-09 11:22:05 · 1158 阅读 · 0 评论 -
32. TCP异常之三次握手
本节来重现TCP可能出现异常的原因中部分为三次握手的出现的问题.服务端没有监听服务端没有监听, 客户端发送ACK而服务端TCP协议返回一个RST段, 客服端调用connect返回错误, 错误类型是ECONNREFUSED.这个实验随便之前的哪一个代码都可以, 只运行客户端的程序, 抓包就可以看到 :SYN后没收到ACK确认报文客户端一直没有收到对端的ACK确认报文, 当超时后继续发送F...原创 2019-02-20 22:10:52 · 604 阅读 · 0 评论 -
31. TCP异常之TCP可能出现异常的原因
本节介绍TCP可能会出现的异常的时候以及部分原因, 提出来的问题大概都会在后面实验中会有所涉及. TCP异常会出现在连接的任何时候, 比如三次握手, 四次挥手等阶段.三次握手TCP在三次握手过程中的每一步都可能出错, 这里也就介绍以下问题.服务端没有监听, 所以服务端TCP协议返回一个RST段, 而客户端收到后立即返回并停止连接. 客服端调用connect返回错误, 错误类型是ECONNR...原创 2019-02-20 22:09:35 · 2368 阅读 · 0 评论 -
27. getsockopt和setsockopt函数
这里两个函数可以用来设置套接字选项或者说属性. 当然套接字选项的函数还有fcntl和ioctl, 但是现在暂时不会涉及到. 本机就来介绍者这两个函数.函数原型两个函数是根据套接字的类别对其进行设置的. 比如前面涉及到的Nagle算法的关闭.#include <sys/socket.h>int getsockopt(int sockfd, int level, int optn...原创 2019-02-20 22:07:58 · 471 阅读 · 0 评论 -
28. TCP协议之Nagle算法与CORK算法
Nagle算法如果有过多的小分组在网络中进行传输, 这会降低网络的利用率. 假如每个分组都只有一个字节数据组成的TCP数据报的话, 也就是糊涂窗口综合症, 这时可想而知整个网络的利用率有多低. 而采用Nagle算法能明显减少上述可能出现的情况, 并提高网络带宽, 减缓网络拥塞.Nagle的规则 :如果包长度达到MSS,则允许发送;如果该包含有FIN,则允许发送;设置了TCP_...原创 2019-02-20 22:06:11 · 778 阅读 · 0 评论 -
23. TCP协议之IP数据报分片
在TCP中MSS和MTU中讲到过分片, 分片 : 当IP数据报的字节大于了MTU的值就需要数据报进行分片, 将数据放入不同的数据报中发送.IP数据报格式接下来会涉及到IP数据报的格式.本节主要涉及IP数据报 : 标记 , 片偏移.IP数据报分片数据分组发送并不一定是按照顺序发送的, 对端也不一定按顺序接收.比如一段数据超过了MTU的值而被分成了1, 2, 3片, 发送时可能是先发...原创 2019-02-20 22:03:52 · 1353 阅读 · 0 评论