自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(72)
  • 收藏
  • 关注

原创 基础回顾----listen函数的backlog参数的本质

在初学网络编程这块时,对listen函数的第二个参数(backlog)简单理解为服务器允许同时连接的客户端个数,但后面总是感觉对这个参数的意义很模糊,在查阅资料后才发现这个参数远远没有表面上那么简单,因此写篇博客总结、记录、巩固一下。先提出两个概念半连接状态队列(syns queue)和完全连接状态队列(accept queue),通过下图可以看到这两个队列的作用:图片来源:关于TCP 半连接队列和全连接队列可以看到linux会将处于SYN_RCVD状态的socket放在半连接队列中,将已经建议好连

2020-08-12 00:43:09 1540 1

原创 为何static不能在类中定义而static const却能在类中定义?

有时候类会声明在头文件中,static 成员变量是属于类的而不属于类实例化的对象,所以若在类中定义static成员变量就与不能在头文件中定义变量的规则冲突。但是为什么static const却能在类中定义呢?因为static const 成员变量会被编译器优化,为编译期常量,编译器不会为其分配内存,更像是宏定义那样,在编译期时,在使用它的地方,用它的值替换它,这一点可以通过代码看到,若我们在类中定义一个static const 成员变量,我们可以打印出它的值,却不能打印出它的地址,因为编译器并没有给它分配内

2020-08-10 12:30:27 627 1

原创 进程池实现----高效的半同步/半异步并发模式的进程池

为何要用进程池?当我们在写并发服务器时,若每当一个客户端连接请求到来时,我们就为其创建一个进程来服务。这样动态的创建进程,无疑是比较耗时的,这将导致较慢的客户端相应。进程池的概念在服务器启动前我们就创建一组进程,我们将这组进程在逻辑抽象成一个池子。当我们需要一个工作进程来处理新到来的客户端请求时,我们可以直接从进程池中取得一个执行实体(进程),而无需动态的调用fork函数来创建进程。相比于动态创建子进程,选择一个已经存在的子进程代价显然要小得多。至于主进程如何选择子进程,有两种方式:主进程使用某

2020-08-09 19:18:37 311

原创 sendmsg和recvmsg的应用----在进程之间传递描述符

在进程之间传递描述符,我们通常会想到fork一个子进程,通过子进程继承父进程打开的描述符,来实现进程之间传递描述符。但是有时候我们需要子进程向父进程传递描述符,或者在没有血缘关系的两个进程之间传递文件描述符,比如客户端向服务端请求打开某个文件或者设备,服务端进行打开操作并把描述符传递给客户端,这样对客户端屏蔽了打开文件或者设备的细节。我们应当注意的是这里传递的描述符不是数值,而是发送描述符进程的PCB中文件描述符表里以该文件描述符为索引的元素----指向File结构体的指针对于上面描述的需求,Linux

2020-07-30 00:16:02 836

原创 Linux进程间通信----信号量

学过操作系统的话,对信号量应该熟悉。当多个进程同时访问计算机资源时,我们需要考虑进程同步问题,以确保任一时刻只有一个进程可以拥有独占式的访问。通常程序对共享资源访问的代码只是很短的一段,但就是这很短的一段代码引发了进程同步问题,我们将这段代码称为临界区。进程同步就是确保任一时刻只有一个进程进入临界区。信号量原语是操作系统为进程同步提供的一种手段。一、什么是信号量信号量是一种特殊的变量,他只能取自然数值,并且只支持两种操作,即p、v操作。假设我们当前有信号量sv。p操作:访问信号量sv,若其值大于0,则

2020-07-21 23:41:17 231

原创 最小堆的实现及应用-----定时器(3):时间堆

基于升序链表的定时器和时间轮都是以固定的频率来调用心搏函数,并在其中依次检测到期的定时器,然后执行到期定时器上的回调函数,这样的定时并不准确,因为可能已有定时器到期了,但是因为心搏函数此时还未调用而无法处理定时任务。设计定时器的另一种思路是:将所有定时器中超时时间最小的一个定时器的超时值作为心搏间隔。这样,一旦心博函数tick被调用,超时时间最小的定时器必然到期,我们就可以在tick函数中处理该定时器。然后,再次从剩余的定时器中找出超时值最小的一个,并将这个设置为下一心博间隔。如此反复,就可以实现较为精准

2020-07-20 21:40:04 896

原创 定时器(2)---时间轮

上一文所说的基于排序链表的定时器在添加定时器时效率很低,而时间轮则解决了这个问题,下图为一个简单的时间轮:指针指向一个槽(slot),其以恒定的速度顺时针转动,每转动一下就指向下一个槽,每次转动称为一个滴答(tick)。一个滴答的时间称为时间轮的槽间隔si(slot interval),它实际为心搏时间。该时间轮有N个槽,其运转一周的时间为N×siN\times siN×si。每个槽指向一条定时链表,每条链表上的定时器具有一个相同的特征:即他们的定时时间相差N×siN\times siN×si的整数倍。

2020-07-18 20:58:25 243 1

原创 定时器(1)---基于升序双向链表定时器处理非活动连接

一个高性能服务器通常需要处理非活动连接,来提升性能和释放计算机资源,我们可以为每个客户端设置一个定时器,其中包含超时时间,处理函数以及函数的参数。通过升序双向链表将所有客户端的定时器组织起来,通过alarm函数定时,当SIGALRM信号到来时,遍历链表来调用超时客户端的回调函数来关闭非活动连接。下面通过代码来展示这一方法。定时器代码:list_time.h:#ifndef _LIST_TIME_H#define _LIST_TIME_H#include<time.h>#inclu

2020-07-18 16:44:53 458

原创 收不到SIGURG信号?

在写利用SIGURG信号处理带外数据时,程序老是收不到该信号,找了很长时间BUG,在网上也搜不到相关内容,所以在此记录一下,防止后面的人跟我踩的是一样的坑,当然这种错误可能就我一个人会犯。我收不到的原因是,SIGURG信号捕捉函数是在accept之后注册的,而客户端发送数据是建立连接后立即开始发送数据的,并且发完数据就直接关闭连接退出了,而服务端检测到对端关闭后也会释放资源退出,这会导致两种情况:1.当带外数据到达时,SIGURG信号的捕捉函数还没注册上,服务端采用的是默认处理动作,即忽略。2.带外数

2020-07-02 20:21:43 468 6

原创 带外数据

带外数据什么是带外数据TCP的带外数据TCP带外数据的发送过程TCP带外数据的接受过程默认接受方式另一种接收方式应用程序如何接受和发送带外数据应用程序检查带外数据是否到达的方法I/O复用系统调用的异常事件SIGURG信号什么是带外数据带外数据用于迅速告诉对方本端发生的重要事情。它比普通数据有更高的优先级,它应该总是立即被发送,不论发送缓冲区中是否有排队等待发送的普通数据。带外数据的传输可以使用一条独立的传输层连接,也可以映射到传输普通数据的连接中。udp没有实现带外数据传输,TCP也没有真正的带外数据,

2020-07-02 19:15:53 795

原创 EINTR

当程序在执行处于阻塞状态的系统调用时接收到信号,并且我们为该信号设置了信号处理函数,在信号处理函数返回后,程序将面临继续执行或不执行慢速系统调用两种选择,默认情况下是系统调用将被中断,并且errno被设置为EINTR。我们可以选择继续执行,有以下两种方法:1.在设置信号处理函数的时候,为信号设置SA_RESTART标志以自动重启被该信号中断的系统调用,但是该方法对某些慢速系统调用无效,比如epoll_wait,poll,seletc等慢速系统调用,即使给信号设置了该选项,也会被中断。具体对那些慢速系统调用

2020-06-30 17:38:52 1496

原创 信号的一种处理模式----统一事件源

信号是一种异步事件:信号处理函数和程序的主循环是两条不同的执行路线。我们希望信号处理函数尽快地执行完毕,以确保该信号不会屏蔽(为了避免一些竟态条件,信号在处理期间,系统不会再次触发它)太久。(由于信号集采用位图这种数据结构,导致在我们屏蔽该信号期间 ,无论该信号到达多少次,我们只能记录一次,所以在当前信号处理函数执行完后,该信号只能触发一次,这当然不是我们希望的,所以信号处理函数执行的越快,越能避免这种问题。)为了使信号处理函数执行的速度变快,我们可以将处理函数的主逻辑放在程序的主循环中,当信号处理函数被

2020-06-30 14:51:53 215

原创 用poll来实现群聊功能

客户端:#include<stdio.h>#include<sys/socket.h>#include<sys/poll.h>#include<sys/types.h>#include<arpa/inet.h>#include<stdlib.h>#include<string.h>#include<errno.h>#include<unistd.h>#include<fcnt

2020-06-29 22:54:01 133

原创 UDP SOCKET 读数据的注意事项

UDP是数据报协议,它的数据单位与TCP不同,是以一个报文为单位,所以我们读取数据时应当注意应用缓冲区的大小,若不能接受一个报文中全部的数据,那么该报文没有被读取到的数据会丢失。...

2020-06-28 15:42:24 327

原创 I/O复用的高级应用三:同时处理TCP和UDP服务

对于同一个端口,如果服务器要同时处理该端口上的TCP和UDP请求,则需要建立两个不同的socket,一个是流socket,另一个是数据报socket,并将它们都绑定到该端口上。下例回射服务器就能同时处理一个端口上的TCP和UDP请求:#include<stdio.h>#include<sys/socket.h>#include<sys/epoll.h>#include<sys/types.h>#include<unistd.h>#in

2020-06-28 13:01:03 272

原创 使用POLLRDHUP和EPOLLRDHUP事件的坑

这两个事件其实是一个东西,分别对应poll和epoll,通常用来判断对端是否关闭,但是当你对某个socket注册POLLIN和POLLRDHUP(EPOLLIN和EPOLLRDHUP)时,在对端关闭时,对于poll来说会一直触发POLLIN + POLLRDHUP事件,epoll也会触发EPOLLIN + EPOLLRDHUP事件,是否一直触发要看epoll是工作在LT模式下还是ET模式下。所以,当我们使用POLLRDHUP(EPOLLRDHUP)事件来判断对端是否关闭时,POLLRDHUP(EPOLLR

2020-06-27 11:22:33 2948

原创 I/O复用的高级应用----非阻塞connect

在使用非阻塞connect时,常常会发生EINPROGRESS错误。这是在对非阻塞desocket调用connect,而连接又没有立即建立的情况下发生的错误,在这种情况下,我们可以调用select、poll等函数来监听这个连接失败的socket上的可写事件。当select、poll等函数返回后,再利用getsockopt来读取错误码并清楚该socket上的错误。如果错误码是0,表示连接成功建立,否则连接失败。非阻塞connect的实现:#include<stdio.h>#include&l

2020-06-26 16:45:36 173

原创 epoll在并发编程中同步问题的解决-----EPOLLONESHOT事件

无论epoll处于LT模式还是ET模式下,一个socket上的某个事件都可能会被触发多次。这在并发编程中会引起一个问题,比如一个线程在读取完某个socket上的数据后开始处理数据,而在处理数据的过程中又触发可读事件,这样会有另外一个线程读取新的数据,这样就会出现两个线程同时操作一个socket的问题。上述问题可以通过epoll中的EPOLLONESHOT事件来解决,对于注册EPOLLONESHOT事件的文件描述符来说,只会触发一次事件,除非使用epoll_ctl函数重置该文件描述符上注册的EPOLLONE

2020-06-25 20:33:54 586

原创 用有限状态机处理http请求

#include<stdio.h>#include<sys/socket.h>#include<sys/types.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<arpa/inet.h>//主状态机有两种状态,当前正在分析请求行,当前正在分析头部字段enum CHECK_STATE{CHECK_STATE_REQUESTLIN

2020-06-24 22:35:17 553

原创 tee函数

tee函数在两个管道文件描述符之间复制数据,也是零拷贝操作,它不消耗数据,所以其源文件描述符上的数据仍然可用于后续的读操作,其函数原型如下:ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags);其参数和上篇splice函数的参数意义相同,但是fd_in和fd_out必须是管道文件描述符,函数成功返回在两个文件描述...

2020-04-21 23:53:06 591

原创 splice函数

该函数用于在两个文件描述符之间移动数据,为零拷贝操作,其函数原型如下:ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags);splice()在两个文件描述符之间移动数据,而无需在内核地址空间和用户地址空间之间进行...

2020-04-21 20:14:46 4740 2

原创 sendfile函数

这个函数顾名思义就是传输文件,其函数原型为:#include <sys/sendfile.h>ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);out_fd参数:为写打开的文件描述符,在2.6.33之前的Linux内核中,out_fd必须引用套接字。从Linux 2.6.33开始,它可以是任...

2020-04-21 17:32:26 1082

原创 网络API----getaddrinfo和getnameinfo函数

该函数可通过知己名获取IP地址(内部使用的是gethostbyname函数),也能通过服务名获得端口号(内部使用的是getservbyname函数)。其是否可重入取决于其内部的gethostbyname和getservbyname函数是否是它们的可重入版本,该函数的定义如下: int getaddrinfo(const char *hostname, const char *serv...

2020-04-20 22:11:54 841

原创 网络API之gethostbyname和getservbyname

这两个函数的头文件为#include<netdb.h>gethostbyname函数原型为:struct hostent * gethostbyname(const char *name);函数作用为:通过主机名来获取主机完整信息,参数指定目标主机的主机名。返回的结构体类型定义如下:struct hostent{ char* h_name; /* 主机名...

2020-04-20 15:00:38 322 1

原创 Leetcode----22. 括号生成

对于每个位置我们都有两种选择(放左括号或右括号),为了生成有效的括号,右括号剩余个数要比左括号的剩余个数大才能放右括号。class Solution { vector<string>v;public: vector<string> generateParenthesis(int n){ dfs(n,n,""); retu...

2020-04-11 16:28:22 92

原创 leetcode----面试题13. 机器人的运动范围

题目链接----------------------->面试题13. 机器人的运动范围很简单的一道搜索题,之前都是用递归做的,这次用栈来实现dfs,其实本质是一样的,帖下代码:int movingCount(int m, int n, int k) { int cnt = 1,sum; int fxy[4][2]={{1,0},{-1,0},{0,1},{0,-1}};...

2020-04-08 21:27:18 121

原创 leetcode----面试题 01.07. 旋转矩阵

题目链接--------------->leetcode----面试题 01.07. 旋转矩阵这个题只要我们自己手动模拟一边旋转过程,很容易就找出规律来。方法一:对于一个num[i][j]num[i][j]num[i][j]来说它旋转后的位置为num[j][n−1−i]num[j][n-1-i]num[j][n−1−i],我们使用一个数组来保存原数组的值,然后双重循环对原数组复制即可。...

2020-04-07 19:53:32 151

原创 leetcode----72. 编辑距离

日常菜的一天????????????题目链接------------------------------------>72. 编辑距离这是一道动态规划问题,我们定义dp[i][j]dp[i][j]dp[i][j] 代表word1的前 i 个字符到word2的前 j 个字符的最少操作次数。需要注意的是,对word1的增加一个字符和对word2删除一个字符是等价的,因为我们只关心操作次数,例如对于ho–&g...

2020-04-06 20:16:57 121

原创 Lettcode----84. 柱状图中最大的矩形

方法一:暴力遍历所有柱子,对于一根柱子将它向左右扩展算出面积,若比最大面积大则更新最大面积。时间复杂度O(n2)O(n^2)O(n2)int largestRectangleArea(vector<int>& heights) { int len = heights.size(); if(len == 0) return 0; in...

2020-04-05 12:40:51 136

原创 leetcode----42. 接雨水

方法一:维护一个栈底到栈顶严格单调递减的单调栈这题需要算出凹面积的总和,我们维护一个单调栈,当我们要插入的柱子不满足单调栈的性质时,会和栈顶的柱子形成凹面,我们将栈顶弹出并计算出凹面的面积,一直重复直到该柱子满足单调栈的性质将其插入。面积的计算方法:(弹出的栈顶柱子的左右柱子的高度最小值−弹出的柱子高度)×(需要插入柱子的位置−弹出的柱子的位置−1)(弹出的栈顶柱子 的左右柱子 的高度最小值...

2020-04-04 14:35:40 111

原创 leetcode----8. 字符串转换整数 (atoi)

题目链接--------------------->8. 字符串转换整数 (atoi)这道题目没什么好说的,就是要对各个情况要考虑全面,要注意细节 int myAtoi(string str) { int len = str.length(),flag = 1; long long int num = 0; int ans = 214...

2020-04-03 23:09:21 97

原创 leetcode----289. 生命游戏

题目链接------------>289. 生命游戏这道题我们按照题目的描述模拟细胞状态变化就可以了,由于是每个细胞根据周围的细胞状态进行变换,并且题目要求所有细胞的状态是同时变换的,所以我们需要一个新的二维数组来存放细胞最初始的状态。 void gameOfLife(vector<vector<int>>& board) { int...

2020-04-02 17:45:54 123

原创 leetcode----1111. 有效括号的嵌套深度

题目链接----------------------------->1111. 有效括号的嵌套深度其实这个题目的意思就是把一个有效括号字符串分成A和B两个字符串,使得这两个字符串的嵌套深度中最大的那个近可能的小。答案不唯一。这个题算是有效括号的升级版吧,最基础的是模拟栈,因为你要保证A和B是有效括号,看到题目我想到的方法是,算出最大的嵌套深度,然后除以二平均分给A和B两个字符串。vec...

2020-04-01 22:11:39 201

原创 leetcode----912. 排序数组

这是一个排序题,都是老生常谈的东西了,之前都是用的排序算法都是通过比较大小进行排序,贴一下不用比较大小的计数排序的代码(不算严格意义的计数排序)vector<int> sortArray(vector<int>& nums) { int len = nums.size(); int max_num = -0x3ffff,min_num = 0x3...

2020-03-31 15:23:54 127 2

原创 Leetcode----面试题62. 圆圈中最后剩下的数字

我想到的方法是模拟,看了一下数据范围肯定超时,想着肯定有数学解法,看了下题解果然是有的。今天又是菜的一天。这是一个经典的约瑟夫环的问题,我们先看一下,题目所给数据的模拟过程。可以看出下一轮的第一个数是当前这一轮所删除数字下一个数向前移动m次,所以我们可以通过反推推出剩下的最后一个数在第一轮时的位置,这个位置的下标即为这个数。公式:(当前位置下标+m) % 上一轮数组长度1.在倒数第二轮...

2020-03-30 14:31:21 114

原创 leetcode----820. 单词的压缩编码(补题)

题目链接---------------->820. 单词的压缩编码这道题只需要判断一个单词是否被其他单词包含(即是否是其他单词的后缀),因为若其被包含则不用为其添加新的编码,编码长度即为不是其他单词后缀  的单词的长度加上每个单词后面补上的#长度方法:1.我们先将整个字符串数组按长度排序(也可以不排序,先将所有的字符串放入哈希表中即可)2.在将该字符数组加入哈希表...

2020-03-29 23:41:05 247

原创 Leetcode---1162. 地图分析

题目链接----------->1162. 地图分析题意大概是找到离陆地最远的海洋区域,返回它离陆地的最近距离。我想到了用bfs来做,但是我想的是把每个陆地节点都走一次BFS,然后跟之前的距离做比较,小的话就更新,算了一下时间复杂度感觉很高过不了,看了题解恍然大悟,太菜了。题解的做法是把所有的陆地节点都放入队列中,只跑一次BFS,最先到达的一定是距离最小的(你细品)。因为把所有陆地节点...

2020-03-29 21:44:03 188

原创 leetcode---914. 卡牌分组

题目链接---->914. 卡牌分组统计每个数出现的次数,所有次数的最大公约数大于等于2则为true否则为false。 bool hasGroupsSizeX(vector<int>& deck) { int n = deck.size(); if(n < 2) return false; ...

2020-03-27 14:47:53 103

原创 leetcode---999. 车的可用捕获量

今天的题也很简单,感觉这几天leetcode的每日一题有点水…题目链接----->999. 车的可用捕获量方法一:扫描其所在的行和列int numRookCaptures(vector<vector<char>>& board) { int len = board.size(); int i,j,x,y,ans = 0,sum = 0;...

2020-03-26 15:20:49 115

原创 leetcode---892. 三维形体的表面积

今天的签到题是比较简单的,我们可先将所有方块的表面积算出来(小方块个数乘6),再减去它们遮住的那部分面积就好了。对于不同柱体之间的遮盖面积,我们每次只要考虑该位置的右边和下边就好了,算法为方块数量较小的柱体的方块数*2。对于柱间遮住的面积为:该柱体(方块数-1)*2。int surfaceArea(vector<vector<int>>& grid) { ...

2020-03-25 20:02:45 112

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除