![](https://img-blog.csdnimg.cn/20201014180756925.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
网络编程实战
ziggy7
这个作者很懒,什么都没留下…
展开
-
网络编程实战框架 五、tcp_server_start(tcpServer) + event_loop_run()
一些结构体event_loop_thread()struct event_loop_thread { struct event_loop *eventLoop; pthread_t thread_tid; /* thread ID */ pthread_mutex_t mutex; pthread_cond_t cond; char * thread_name; long thread_count; /* # connections h原创 2020-11-10 14:16:19 · 302 阅读 · 0 评论 -
网络编程实战框架 四、tcp_server_init()
一些结构体TCPServerstruct TCPserver { int port; struct event_loop *eventLoop; struct acceptor *acceptor; connection_completed_call_back connectionCompletedCallBack; //连接建立之后的callback message_call_back messageCallBack; //数据读到buffer之原创 2020-11-04 14:37:19 · 635 阅读 · 0 评论 -
网络编程实战框架 三、acceptor_init()
一些结构体acceptorstruct acceptor{ int listen_port; //监听端口 int listen_fd; //listenfd} ;主函数调用//初始化acceptor struct acceptor *acceptor = acceptor_init(SERV_PORT);流程此函数完成了socket、bind、listen等流程,并返回acceptor结构体//socket、bind、listenstruct accepto原创 2020-11-04 10:04:17 · 88 阅读 · 0 评论 -
网络编程实战框架 一、总体思路
设计需求●采用 reactor 模型,可以灵活使用 poll/epoll 作为事件分发实现。●必须支持多线程,从而可以支持单线程单 reactor 模式,也可以支持多线程主 - 从 reactor 模式。可以将套接字上的 I/O 事件分离到多个线程上。●封装读写操作到 Buffer 对象中。按照这三个需求,正好可以把整体设计思路分成三块来讲解,分别包括反应堆模式设计、I/O 模型和多线程模型设计、数据读写封装和 buffer。主要设计思路反应堆模式设计 反应堆模式主要是设计一个基于事件分发和回调原创 2020-11-04 09:52:58 · 241 阅读 · 0 评论 -
网络编程实战框架 二、event_loop_init()
一些结构体event_loop一个无限循环着的事件分发器,一旦有事件发生,它就会回调预先定义好的回调函数,完成事件的处理。struct event_loop { int quit; //类似于poll或者epoll,可以让线程挂起,等待时间发生 const struct event_dispatcher *eventDispatcher; // 对应的event_dispatcher的数据 //声明为void*,poll和epoll的数据对象都能放入原创 2020-11-04 09:52:42 · 254 阅读 · 0 评论 -
网络编程实战30 同/异步I/O(proactor)
同步I/O阻塞I/O:阻塞I/O发起的read请求,线程会被挂起,一直等到内核数据准备好,并拷贝数据,拷贝过程完成,read请求调用才返回。非阻塞I/O(轮询):非阻塞的read请求在数据未准备好的情况下立即返回,应用程序可以不断轮询内核非阻塞I/O(I/O多路复用):轮询的做法太消耗资源,因为在轮询的过程中进程啥也不能干。异步I/Oaio_read会立即返回,拷贝完成了会通知。整个拷贝过程是异步的,内核自动完成的,和前面的同步操作不一样,应用程序并不需要主动发起拷贝动作。区别原创 2020-08-26 09:43:56 · 199 阅读 · 0 评论 -
网络编程实战29 使用epoll和多线程模型
框图为什么要使用epollepoll比poll效率高,见三者比较的文章如何切换到epoll我们的网络编程框架是可以同时支持 poll 和 epoll 机制的,那么如何开启 epoll 的支持呢?ib/event_loop.c 文件的 event_loop_init_with_name 函数是关键,可以看到,这里是通过宏 EPOLL_ENABLE 来决定是使用 epoll 还是 poll 的。struct event_loop *event_loop_init_with_name(char *t原创 2020-08-24 18:50:07 · 356 阅读 · 0 评论 -
网络编程实战28 多线程使用poll处理连接I/O事件(主从reactor)
使用多线程的原因●单reactor线程既分发连接建立,又分发I/O,忙不过来,会使得客户端连接成功率偏低。●新的硬件技术不断发展,多核多路CPU已经得到极大应用,单reactor不能充分利用CPU资源主-从reactor模式思想: 主反应堆线程只负责分发Acceptor连接建立,已连接套接字上的事件交给sub-reactor负责分发。其中sub-reactor的数量可以根据CPU的核数来灵活设置。主-从reactor+worker threads模式思想: 与主-从reactor模式的区别原创 2020-08-24 17:22:17 · 343 阅读 · 0 评论 -
网络编程实战27 使用poll单线程处理所有I/O事件
事件驱动例子:GUI中的控件,如Button有个对应的onButtonClick函数。一个无限循环的事件分发线程在后台运行,一旦用户点击了按钮,一个事件会被产生并放置到事件队列中,然后事件分发线程找到相应的回调函数并执行它。优点:事件驱动的好处是占用资源少,效率高,可扩展性强,是支持高性能高并发的不二之选。基于套接字的事件驱动程序事件驱动模型,也被叫做反应堆模型(reactor),或者是 Event loop 模型。这个模型的核心有两点。一、存在一个无限循环的事件分发线程,或者叫reactor线程原创 2020-08-24 17:00:06 · 143 阅读 · 0 评论 -
网络编程I/O模型
任何一个网络程序,所做的事情可以总结成下面几种:●read:从套接字读取数据●decode:对收到的数据进行解析●compute:根据解析之后的内容,进行计算和处理●encode:将处理之后的结果,按照约定的格式进行编码●send:通过套接字把结果发出去fork概念: 使用fork创建子进程为每个到达的客户连接服务。缺点: 随着客户数的变多,fork 的子进程也越来越多,即使客户和服务器之间的交互比较少,这样的子进程也不能被销毁,一直需要存在。使用 fork 的方式处理非常简单,它的缺点原创 2020-08-24 16:33:09 · 163 阅读 · 0 评论 -
网络编程实战26 阻塞I/O和线程模型(线程池)
相对于进程的优势线程上下文切换的开销比进程小的多。上下文切换:代码被CPU执行的时候,是需要一些数据支撑的,比如程序计数器告诉CPU代码执行到哪里了,寄存器里存了当前计算的一些中间值,内存里放置了一些当前用到的变量等,从一个计算场景,切换到另一个计算场景,程序计数器、寄存器等这些值重新载入新场景的值,就是线程的上下文切换。线程相关函数创建线程:每个线程都有一个线程 ID(tid)唯一来标识,其数据类型为 pthread_t,一般是 unsigned int。pthread_create 函数的第一个原创 2020-08-20 09:57:38 · 143 阅读 · 0 评论 -
网络编程实战25 阻塞I/O和进程模型(传统方式)
创建子进程函数:使用fork函数创建子进程pid_t fork(void)返回:在子进程中为0,在父进程中为子进程ID,若出错则为-1使用:父子进程通过返回值来区别if(fork() == 0){ do_child_process(); //子进程执行代码}else{ do_parent_process(); //父进程执行代码}回收进程函数:有两种方式可以在子进程退出后回收资源,分别是调用 wait 和 waitpid 函数。pid_t wait(int *statloc原创 2020-08-19 17:18:54 · 140 阅读 · 0 评论 -
网络编程实战24 C10K问题:高并发模型设计
C10K问题C10K:如何在一台物理机上同时服务 10000 个用户?这里 C 表示并发,10K 等于 10000。得益于操作系统、编程语言的发展,在现在的条件下,普通用户使用 Java Netty、Libevent 等框架或库就可以轻轻松松写出支持并发超过 10000 的服务器端程序,甚至于经过优化之后可以达到十万,乃至百万的并发,但在二十年前,突破 C10K 问题可费了不少的心思,是一个了不起的突破。操作系统层面支持10K个连接需要考虑什么方面?从下面可以看出,C10K问题在系统资源方面可以解决原创 2020-08-16 16:07:34 · 214 阅读 · 0 评论 -
select、poll、epoll
select作用:select 函数就是这样一种常见的 I/O 多路复用技术,使用 select 函数,通知内核挂起进程,当一个或多个 I/O 事件发生后,控制权返还给应用程序,由应用程序进行 I/O 事件的处理。参数:int select(int maxfd, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout);返回:若有就绪描述符则为其数目,若超时则为0,若出错则为-1原创 2020-08-13 20:51:14 · 208 阅读 · 0 评论 -
网络编程实战22 非阻塞I/O
阻塞和非阻塞阻塞I/O:在调用阻塞I/O完成某个操作时,应用程序会被挂起,等待内核完成I/O操作,此时CPU切换到了其他进程,网络程序这时就得不到CPU的时间非阻塞I/O:调用非阻塞I/O时,内核会立即返回,不会把CPU时间切换给其他进程。非阻塞I/O读写注意:●read 总是在接收缓冲区有数据时就立即返回,不是等到应用程序给定的数据充满才返回。当接收缓冲区为空时,阻塞模式会等待,非阻塞模式立即返回 -1,并有 EWOULDBLOCK 或 EAGAIN 错误。●和 read 不同,阻塞模式下,原创 2020-08-13 19:52:09 · 157 阅读 · 0 评论 -
网络编程实战 期中作业:ls、pwd、cd服务器
要求请你分别写一个客户端程序和服务器程序,客户端程序连接上服务器之后,通过敲命令和服务器进行交互,支持的交互命令包括:pwd:显示服务器应用程序启动时的当前路径。cd:改变服务器应用程序的当前路径。ls:显示服务器应用程序当前路径下的文件列表。quit:客户端进程退出,但是服务器端不能退出,第二个客户可以再次连接上服务器端。客户端可以指定待连接的服务器端 IP 地址和端口。在输入一个命令之后,回车结束,之后等待服务器端将执行结果返回,客户端程序需要将结果显示在屏幕上。注意点select调原创 2020-08-13 10:48:43 · 442 阅读 · 0 评论 -
网络编程实战18 增强程序的健壮性
对端异常状况17讲中接触了一些情况,比如通过read等调用,通过对EOF的判断,防范对方程序崩溃。int nBytes = recv(connfd, buffer, sizeof(buffer), 0);if (nBytes == -1) { error(1, errno, "error read message");} else if (nBytes == 0) { error(1, 0, "client closed \n");}但是如果服务端完全崩溃或者网络中断,如果是阻原创 2020-08-12 16:20:53 · 184 阅读 · 0 评论 -
网络编程实战17 TCP并不总是可靠
TCP故障模式感知TCP链路的方式有限,一种是read为核心的读操作,另一种是write为核心的写操作无FIN包网络中断:TCP感觉不到连接异常●情况一:阻塞在read调用上,会一直阻塞下去,可以用超时来解决●情况二:先调用write发送数据流,接下来阻塞在read上,结果会不同,TCP协议栈会不断尝试将发送缓冲区的数据发送出去,重传一定次数后,协议栈会标识该连接异常。阻塞的read会返回TIMEOUT的错误信息,如果程序还在往这条连接写数据,写操作会立即失败,返回SIGPIPE信号系统崩溃:原创 2020-08-10 20:50:25 · 166 阅读 · 0 评论 -
网络编程实战16 TCP流
TCP是流式协议发送端:如调用了send函数发送了hello和world报文,实际的发送情况有很多种,可能两个报文在相同的分组,也可能在不同的分组。不应该觉得数据流和TCP分组一一对应,因为发送缓冲区的存在。接收端:●hello 和 world 的顺序肯定会保持,这个是TCP严格保证的。●如果有TCP分组丢失,后续分组到达会被缓存,直到丢失的分组到达。最终形成可以被读取的数据流。网络字节排序大端字节序和小端字节序:●大端:将数据的高字节放在起始位置●小端:将数据的低字节放在起始位置转换函数原创 2020-08-10 17:42:50 · 250 阅读 · 0 评论 -
网络编程实战 15 地址已经被使用
例子服务端Ctrl + C在服务器关闭连接,重启服务器端程序可能会重启失败,报错信息为:bind failed: Address already in use。原因:TIME_WAIT通过服务器端发起的关闭连接操作,引起了一个已有的 TCP 连接处于 TME_WAIT 状态,正是这个 TIME_WAIT 的连接,使得服务器重启时,继续绑定在 127.0.0.1 地址和 9527 端口上的操作,返回了 Address already in use 的错误。解决:重用套接字选项 一个TCP通过四元组来原创 2020-08-10 11:29:58 · 183 阅读 · 0 评论 -
网络编程实战 14 UDP的已连接
客户端的connect使用UDP是无连接协议,但是也可以使用connectint socket_fd; socket_fd = socket(AF_INET, SOCK_DGRAM, 0);...if (connect(socket_fd, (struct sockaddr *) &server_addr, server_len)) { error(1, errno, "connect failed"); }服务端未开启的情况下,运行结果是recvfrom failed: Conn原创 2020-08-10 10:50:26 · 139 阅读 · 0 评论 -
网络编程实战13 小数据包应对:TCP中的动态数据传输
调用数据发送接口后数据只是从应用程序拷贝到了系统内核的发送缓冲区中。由TCP协议栈来负责发送出去。流量控制**原因:**发送端和接收端都有自己的处理能力和存储规模,所以需要流量控制。**发送/接收窗口:**发送窗口和接收窗口时TCP连接的双方,一个作为生产者,一个作为消费者,为了达到一致协同的生产-消费速率,而产生的算法模型实现拥塞控制**原因:**TCP要考虑在多个连接共享在有限的带宽上,兼顾效率和公平性的控制常用算法:●慢启动通过一定的规则,慢慢地将网络发送数据的速率增加到一个阈值。超过原创 2020-08-07 20:22:45 · 277 阅读 · 0 评论 -
网络编程实战 Keep-alive和心跳检测无效连接
检测连接的原因需要有机制来发现TCP连接是有效的还是无效的。比如客户端突然崩溃,服务器端可能几天内都维护一个无用的TCP连接TCP Keep-Alive选项**原理:**定义一个时间段,这个时间段内如果没有任何连接相关的活动,TCP保活机制就会开始作用,每隔一个时间间隔,发送一个数据很少的探测报文,如果连续几个探测报文都没有得到响应,则认为当前的TCP连接已经死亡,系统内核将错误信息通知给上层应用程序。参数:上述的可定义变量,分别被称为保活时间、保活时间间隔和保活探测次数。在 Linux 系统中,这原创 2020-08-07 18:50:29 · 614 阅读 · 0 评论 -
网络编程实战 11优雅/粗暴关闭连接(shutdown与close)
11 优雅/粗暴关闭连接优雅关闭:TCP连接线关闭一个方向,此时另外一个方向还是可以正常进行数据传输。 如客户端主动中断连接,不再写入数据。服务端读完客户端数据后就不会再有新的报文到达,但是TCP连接并不一定关闭,很可能服务端在对客户端最后报文进行处理,完成这些操作之后,服务端把结果通过套接字写给客户端,最后服务端才关闭剩下的半个连接,结束TCP连接。粗暴关闭:两边都关闭了,服务端处理完的信息没有正常传给客户端。close函数int close(int sockfd)功能:对套接字引用计数减一原创 2020-08-07 16:27:50 · 710 阅读 · 1 评论 -
网络编程实战 10 TIME_WAIT
10 TIME_WAIT(发起连接终止的一方才会进入)发生场景: TIME_WAIT状态的连接过多,多到把本机可用的端口耗尽,对外表现的症状就是不能正常工作了。过了一段时间后,处于TIME_WAIT的连接被系统回收并关闭,释放出本地端口,可以正常工作。这样周而复始,便会出现一会不可以,一会可以正常工作的现象。四次挥手: TCP 连接终止时,主机 1 先发送 FIN 报文,主机 2 进入 CLOSE_WAIT 状态,并发送一个 ACK 应答,同时,主机 2 通过 read 调用获得 EOF,并将此结原创 2020-08-07 16:27:02 · 157 阅读 · 0 评论 -
网络编程实战 基础篇
1 TCP/IP2.客户端/服务端还有一点需要强调的是,无论是客户端,还是服务器端,它们运行的单位都是进程(process),而不是机器有两种截然不同的传输层协议,面向连接的“数据流”协议 TCP,以及无连接的“数据报”协议 UDP。套接字和地址4.用套接字建立连接api见https://time.geekbang.org/column/article/116042三次握手具体的过程:1.客户端的协议栈向服务器端发送了 SYN 包,并告诉服务器端当前发送序列号 j,客户端进入 SY原创 2020-08-01 20:48:43 · 207 阅读 · 0 评论