- 博客(50)
- 收藏
- 关注
原创 恢复写作,谈谈网络连接的硬件设备
由于为了准备春季招聘,博客断更了相当长的一段时间,最近繁杂的事情也差不多处理完了,恰好今天是个好日子,61儿童节,那么就开始恢复写作,当然好久没有写了,一上来就不肝干货了,先谈谈些简单的东西。就是网络中常用的一些硬件设备,例如中继器,集线器,路由器,交换器,网桥,Modena(猫) 等连接设备。我将简要的说说它们的功能。 谈这些之前我先列出经典的osi七层网络模型这是由iso...
2018-06-01 23:19:25
484
原创 select,poll和epoll的区别
Select就是通过监听事件写入到一个32个元素 累计1024位的long数组中(就是fed_sets结构体的内容),用户加入监听位,如果有监听事件发生就会改变位的标志。但这样会有两个缺点,一是监听的数量被限制在了1024(三种事件:可读,可写,异常),而且复杂的位操作,即使提供了多个操作宏,仍会感到编程的繁琐,还有每次调用select(是每次,进入循环后每次使用select前都要做得事)要重新把...
2018-02-09 16:59:51
435
原创 I/O复用---select
I/O复用也是提高服务器性能的一种非常高效的方式,它的原理是什么呢? 我们知道服务器在 接受新的客户端链接,接受已连接客户端发来的数据 等事情上不总是连续的,持续的。假如 一个服务器不使用多线程编程的话,只用一个main线程只能做到和一个客户端链接,接受数据。然而这个客户端只 和服务器链接一次,并且发送数据也不是特别频繁,特别持续的。那么这个服务器可以说是大部分时间在无谓的等待客户端...
2018-02-09 16:54:19
380
原创 线程池网络编程
多线程编程中,每有一个新连接时就会创建一个新的线程去维护连接进行收发数据,但是这会有一个问题,就是频繁的线程创造结束会使系统内核的负担加重,对于执行任务的效率也相对低下,因为还要多出创造线程的时间。 那么如何提高效率,减轻内核的负担呢?我们知道主要原因是由于频繁的创建线程。想要改善效率 不可能选择不创建线程。那只能让线程创建的时间提前,并且不会频繁的再结束再创建。因此就有了线程池的提出。 线...
2018-02-09 16:53:46
515
原创 多线程网络编程
与多进程编程对比: 1 创建多进程相比起创建多线程会 消耗大量的系统资源 2 进程结束比起线程结束,释放的资源也更多,子进程很快结束,系统负担加重 3.多线程由于在同一个进程中,很多资源是共用的。所以线程间数据共享也非常高效快捷。需要注意的两点是: 1.由于多线程在一个进程中,一个进程只有一个pcb,因此不需要考虑主线程和函数线程没有全部close,...
2018-02-09 16:53:01
1376
原创 多进程网络编程
本文概述如何使 服务器同时 连接处理 客户端们。 即服务器的一个进程只负责接受 请求连接的客户端。而具体如何跟各个客户端发送数据交给自己创造的子进程去完成。 用TCP协议来举例。 服务器在创造套接字,并用套接字创建监听队列后,陷入循环,循环里负责的是只要accept接受到了客户端的链接,就会fork出一个子进程,子进程里和客户端去具体的send recv。而父进...
2018-02-09 16:52:28
413
原创 IPV4报头及IP分片
IP协议是无连接,不可靠,无状态的。无连接就是指通讯时不能长久的维持对方信息,保持连接。不可靠就是不能保证数据准确的发送给接受方,可能会丢失,变错,截断等。无状态就是指发送的数据可能是乱序的重复的。至于为什么IP协议的特性是这样的。为什么TCP协议又是有连接的,可靠的,无状态的。那就得从控制协议的报头段来分析原因了。不同的协议,不同的报头,因此表现出来的特性也是区别很大的。IPv4的报头示意图是这...
2018-02-09 16:51:45
6880
1
原创 网络编程 TCP
网络编程的传输层协议一般分为UDP和TCP 其中TCP协议是面向连接的,可靠的,流式服务的协议。简而言之就是安全性完整性更高的,但效率低于UDP的协议。 本文将重点涉及linux下具体的采取TCP协议的网络编程代码实现。 首先最基本的要有两份代码,即服务器端和客户端各一份。 服务器端编程流程如下:1.首先要创建一个套接字socket,其本质为文件描述符 Int...
2018-02-09 16:50:14
331
原创 C和C++的区别(下)
4. const 的使用c语言里const是常变量,而c++里是常量,即立即数。因此c语言里const修饰的变量并不能作为初始化数组长度的下标。而c++里const修饰的变量编译时就被当作立即数,可以当作数组初始化下标 c语言里用const修饰的值可以不初始化,只是之后再没有机会对这个const修饰的变量赋值了。因此我们可以总结出c语言里const定义的常变量和一般变量的区别很小,只是常变量定义后...
2018-02-09 16:49:43
283
原创 C和C++的区别(上)
c和c++的区别先总结4点1. 函数的默认值C++可以给函数定义或声明时给参数赋初值(c语言后来制定的c99标准也能给默认值,但由于现在普遍学习的是c89标准,因此没有此功能)使用默认值的好处是什么?使用默认值的原理又是什么?使用默认值有何规则限定?请接着看。比如main函数先定义俩变量int a;int b;然后调用sum(a,b)的时候压入参数的时候的时候执行的汇编就是Move eax,d...
2018-02-09 16:49:18
463
原创 函数调用栈
我们常用函数,知道使用函数时会跳到函数定义的代码段去执行,然后执行完后再返回到调用函数去,但以下的一些问题却仍不清楚。这个调用过程的原理是什么调用函数前要做什么事情函数的参数是如何传递的如何跳转到被调用函数执行完被调函数后如何返回调用函数并且保证能接着运行要知道这些,需要结合代码的反汇编来看。写了一段简单的函数调用的代码以下为main函数的反汇编其中ebp为栈底指针,esp为栈顶指针。可以看到我们...
2018-02-09 16:48:38
516
原创 编译和链接
我们写的代码是如何变成程序能被计算机执行呢?要运行必须先把"一些东西"加载到内存里边,把什么"一些东西"加载到内存里面? 其实我们的代码就产生了两种东西,一种是数据,一种就是指令. 而数据肯定不能混乱着放在一起,必定有区分区域,那么有什么区域呢?划分依据又是什么? 程序跑起来后,不会直接把数据直接搞到物理内存上,因为操作系统要屏蔽底层的差异,统一管理资源的分配。因此系统会先给每个程序一个...
2018-02-09 16:48:04
417
原创 线程同步与线程安全
1线程同步 同步:多线程访问临界资源时,必须进行同步控制,多进程或者多线程的执行并不完全是绝对的并行运行,又可能主线程需要等待函数线程的某些条件的发生。 多线程的临界资源有全局数据,堆区数据,文件描述符 同步控制方式: 1.1信号量 需要用到头文件semaphore.h 获取: int sem_init(sem_t *sem,int pshared...
2018-02-09 16:47:32
4825
原创 线程
线程是什么 线程是进程内部的一条执行序列(执行流),每个进程至少有一条执行序列:main的执行体。进程可以通过线程库创建N条线程,新建的线程为函数线程,main是主线程。虽然感觉是进程包含着线程,进程由线程组成,但是进程提出的概念比线程概念要早。 线程与进程的区别 1.进程是资源分配的最小单位,线程是CPU调度的最小单位。 2.线程是轻量级的进程 3.管理方式不一样。进程是pcb管理...
2018-02-09 16:47:09
307
原创 进程通讯(五)--共享内存
共享内存就是俩进程共同拥有的内存,一般执行一个程序,会给内存上分配该进程的空间吧。 如果两个进程有一部分是使用共享内存,那么这俩进程其他部分会各自分配自己的内存空间,而使用共享内存的地方只会分配一个共有的内存空间,也就是说这部分共享内存空间都属于这两个进程,这部分空间对于这俩进程来说都是自己的。共享内存本身不难理解,使用起来也无非是介绍几种函数,熟悉下用法。和其他IPC比较一下,还是很容易的。...
2018-02-09 16:46:43
293
原创 进程通讯(四)--消息队列
消息队列和管道很像。但它比起管道不需要固定进程的只读和只写,通讯间的进程都可以读写,并且支持多个进程。 而消息队列发送的消息 实际是一个消息类型和实际的消息。消息类型是什么?它其实是一个长整型数字,具体多少完全由用户来定义,为的是读消息时可以根据这个类型来调整读取的优先级顺序。 所以说消息队列发送的是数据块,一般发送的消息就定义为以下的结构体。 struct msg{ long type;//...
2018-02-09 16:46:21
287
原创 进程通讯(三)--信号量
信号量虽然也是进程通讯的一部分,但比起其他的通讯方式比如管道,消息队列这些直接发送数据的形式不太相同。主要起到控制同步异步的作用。 何为同步异步?听到同步不要因为这个“同”字就联想到俩进程同时运行。恰恰相反,同步往往要求一个进程等待另一个进程而达到协同作用。比如AB俩进程,A进程执行到了某段代码需要 B进程运行返回的数据 ,那么A就会等到了B进程执行直到B返回了A需要的数据时,A才会继续执...
2018-02-09 16:45:53
293
原创 进程通讯(二)--无名管道
无名管道是父子进程间的通讯。无名的管道创建使用完全是在内存中。甚至连有名管道要创建的管道文件都没有。 有名管道的管道文件虽然没有大小,但好歹磁盘中有个标记,可以被需通讯的进程们看到共同使用。而无名管道的管道完全隐藏在一个程序的代码中,在进程运行时创建销毁,正是因为这个特点,所以限制了通讯的范围。 无名管道创建打开的函数 int pipe(int fd[2]); 参数其实已经退化...
2018-02-09 16:45:27
338
原创 进程通讯(一)--有名管道
进程间通讯的意义很多书上都有说,总之是非常重要的一部分,就不多啰嗦了,简单来说是为了完成进程间的协作功能。 然而进程间的通讯方式也不少,信号,信号量,管道,共享内存..... 今天先来说说管道中的有名管道。当然有有名管道自然也有无名管道。至于他俩的区别,我们暂且记着有名管道是可以让同一台计算机上的任意两个无关系的进程通信。而无名管道则是必须需要通信的进程间存在关系,比如父子进程。 有名管...
2018-02-09 16:44:49
308
原创 如何获取两个单链表交点
之前的一篇博客《如何判断两条单链表是否有交点》只说了如何判断是否有交点,但并没有提及如何得到交点。 设置数组分别存储两条链表所有节点的地址,然后一 一比较?可行是可行,不过空间时间复杂度太高,不建议使用。 那有没有更高效的方法呢?方法1 从相交链表的特点来切入分析,看看下面这张图。 一般来说,相交链表会自相交点后有一段公共区域。绿色圈起部分。然而这两条红色A和蓝色B链表的长度差别是不是就是进...
2018-02-09 16:43:46
970
原创 单链表有关 环 的问题
说起关于单链表的环,无非以下几种常见问题 。 1求单链表是否有环 。 2求单链表的入环点。 3求环的长度。 对于问题1,记得我第一次接触的时候,比较暴力,直接定义了个数组存放链表所有节点的地址。 遍历链表每读到下一个节点的时候,都要和已知结点的地址数组比较,看是否相同。这种解法的优点 仅仅是的确很好想,但时间复杂度 空间复杂度都很高。 因此就要寻找更优的解法,我起初的那个很差...
2018-02-09 16:42:14
381
原创 原子操作
什么是原子操作,之前在线程同步 中提到过锁的概念,锁就是个原子操作,即锁实现的全部步骤必须看成一步,cpu切换的时候不能把原子操作切开。 为什么不能切开了。用锁举例,我们在思考锁是如何运行的,简单的想,既然lock()为上锁,它起码要分为1.判断是否还有锁2.如果有锁就上锁,没锁就等着。这俩步,这还是我们以宏观思维想的,然而计算机真正的要实现可能需要的步骤还要更多。如果cpu切换的时候把 实现...
2018-02-09 16:41:32
456
原创 线程同步----信号量
上篇文章《线程同步---睡觉与唤醒》遗留了一个问题,就是会出现死锁的情况。所以为了解决这个问题,又要引入一个新的同步概念,那就是信号量。 起初我个人在理解的时候陷入了一个奇怪的圈子,就总凭感觉和名字认为这个信号量是不是一个储存我之前失效信号的容器,让后在需要之前信号的时候在重新调用信号。 其实没有那么复杂。书上一堆绕来绕去的话令刚接触的人的确不太好想,总之先忘了上篇讲到的sleep和w...
2018-02-09 16:40:43
582
原创 线程同步----睡觉与唤醒
从上一篇文章《线程同步----锁》中我们了解了解决线程同步中最基本的一些问题,那就是如何用 锁 来保护合作线程们的临界区数据不被重复修改。但是从这里引出了一个问题,那就是如果一个线程A先进入了临界区且上了锁,等到B线程也到了临界区前发现锁是锁的,那么B只能等待直到A线程执行完临界区代码才能继续往下执行,这样就会导致cpu被浪费的占用,因为B没有做任何事情,只是等待。 因此为了提高系统的cpu利用率...
2018-02-09 16:40:07
526
原创 线程同步----锁
线程同步就是多个线程完成同一任务而进行的协调不违反规则的合作过程。 例如线程A和线程B的合作任务就是将初值为0的变量x 加为1。程序结束后,x的值应该为1才是我们想要的。如果x没有被++仍为0,或者++了2次变为2了,都是失败的结果。 用两段伪代码模拟一下 int x=0; A: B:if(...
2018-02-09 16:39:09
129
原创 Linux写实拷贝技术
何为写时拷贝技术?这就得先讲讲linux的分页加载机制。 分页加载机制就是linux把内存划分成很多的小块,进程中的数据按照某种对应关系(页表)放入内存中。 这么做的目的是为了提高内存的使用率。可以不必让一个进程中的所有东西都连着放在一起。 连着放在一起的弊端是。如果A进程释放后。假如A进程使用的内存非常少。其他进程都无法使用A进程占的这块内存,因为它太小了放不下。这样就存在内存利用率低...
2018-02-09 16:38:16
1354
原创 大数据处理之哈希表(二)--出现频率最多的top xxx 位
上篇文章中只是求了出现频次最高的值,可是大数据处理往往需求的是top 10 ,top 100或者某一段区间的数据。显然只定义一个Hash a是不能放下的。如果是求出现频次top100呢?最起码定义 Hash arr[100]吧。比如拿计数器10000长度和数据范围为32767来说。我们最少要分4次,分别是数据取余4后 0 1 2 3的四种情况第一次余数为0,即4的倍数这一组,我们是不是要先算...
2018-02-09 16:37:22
2401
原创 大数据处理之Hash哈希表(一)
现在的网络公司对于数据的处理的非常看重的。比如拿百度来说,10大热搜词就是从海量的用户搜索的数据中找到的,我们想的很简单,只要把所有用户搜索的数据按搜索次数 排列下来,随便用个快排?归并?取前10种出现频次最高的不同的数据就好了,可是用户搜索的数据实在是太多了。使用快排归并那种内部排序是需要我们使用电脑内存的,现在电脑一般都是4-8G的内存。这可能连数据百分之1都存放不下。数据都不齐全,何谈排序...
2018-02-09 16:36:07
898
原创 朴素查找子串算法和KMP算法
如何在一个字符串查找子串呢?按照我们以前学过的查找方法无非是这样的。 假如就给定字符串A为“ababcabcd.....”,设要从A查找的子串a为"abc",我们就同时遍历A串,和a串,分别用i和j记录遍历的下标,如果A串的i和a串的j 各自对应的字符一样,我们就让i,j同时往后+,然而大部分情况是i和j还没到它们各自的终点就出现匹配失败了。匹配失败子串的i要置0,j退回到j这轮...
2018-02-09 16:35:26
1411
原创 浅谈5中io模型和同步io、异步io及R模式P模式
五种io模型: 阻塞io模型 非阻塞io模型 io复用模型 信号驱动io模型 异步io模型 其中阻塞与非阻塞 阻塞io:就是函数调用后,会被挂起,直到内核接受到了io的读写,拷贝到了应用进程的用户态后,函数才返回 非阻塞io:就是函数调用后,立刻返回结果,这个结果告诉调用函数者内核是否接受并完成了io的读写阻塞io 非阻塞io io复用 信号驱动io。这四个都可以认为是同步io...
2018-02-09 01:18:38
672
原创 归并排序
研究过归并排序和堆排序的时间复杂度的朋友们应该知道它们的时间复杂度都是nlog2n。堆排序是利用了完全二叉树,做了很多次堆调整才达到了排序的目的。相关堆排序的内容可以看看选择排序的升级---堆排序,在此不多赘述。 其实归并排序也是形似二叉树。简单来讲就是分而治之的思想。谈到 ‘分’很容易想到快速排序,快排也是分。但它是把数列从枢轴点分开。让点的边左都小 右边都大(降序则相反) ,快排分
2017-10-07 18:56:17
277
原创 快速排序的非递归实现
快速排序的思想是先从一数列中找出一个枢轴点,这个枢轴点左边的数都比它小,右边的数都比它大,也就是说枢轴点的位置已经是有序的了。例如 5 1 7 9 2 3 8 使用一次快速排序后会变成这样· · · 5 · · ·。1,2,3会在5的左边,7,8,9在5的右边,5在第四个位置,5是枢轴点,且不会再变动了。 如果最终排序完毕,数列会是 1 2 3 5 7 8 9
2017-10-07 18:55:31
1551
原创 快速排序的优化
优化1通过时间复杂度来切入看看,最好情况为nlog2n,最坏情况为n^2。是什么导致差距如此之大呢? 最好情况就是每次分段的时候,那个分段的点都在待分段数列的中间位置,因此分布非常的平均,所有分段路线,也就是递归的层次是一样的。大家同时分到每段是1个数据的层次。 最坏情况就是顺序,每次分都是左边有,右边没有,导致右边很快就分完了,左边却一直往下分,最后就变成了0n^
2017-10-07 18:52:38
557
1
原创 快速排序 常考排序算法
冒泡排序是交换排序,它是非常慢的,比起几种简单排序,例如选择,插入排序。冒泡排序的时间性能要差的多。因为总要交换数据,只是两个两个的比,不仅逻辑判断多,交换数据的频次也高。 但交换排序就如此失败吗。不,它反而是很成功的,因为它有个顶梁柱。那就是快速排序。 快速排序听着就很快,实际效果来说更快,如果再加入优化,那就快上天了,如果再把几种优化一融合。也许,这就是排序中的王者吧!
2017-10-07 18:51:42
357
原创 堆排序 选择排序的升级
选择排序的思想是每次选择未排序列中最小值的下标,使它对应的值与未排序数列中第一个的值交换内容。从而达到选择的目的。 而堆排序就是每次调整后,选出最大值在堆顶,然后使堆顶放入数列末尾,然后数列长度减1,这样就总使未排数列中的最大值放在未排数列的最后一位。然而怎么确定数列中最大的数呢,如果遍历未排数列 一个一个去比,那显然就是一般的选择排序了但我们要升
2017-10-07 18:50:41
296
原创 希尔排序 插入排序的升级
直接插入排序我们是知道的,它比冒泡和选择快的原因是数据交换的次数相对较少,不像冒泡那样,每次内循环遍历时两个两个数比较然后换来换去,如果是完全反序的,那就得每次都进行交换操作,交换操作可比逻辑判断操作要费时多,这也是之前问的,为什么时间复杂度明明差不多,但运行时间却天差地别,冒泡排序排10万个数据的时候居然用了1分多种。然而要减少交换操作,那就需要序列向有序化靠拢,这样实际的交换数据操作减
2017-10-07 18:49:51
279
原创 直接插入排序
直接插入排序比起冒泡和选择稍微难理解一点,不过也好,毕竟是简单排序,也就是那种比一目了然多想几下的程度。 它的基本思想是什么呢? 插入插入无非就是插入,插入哪啊?插入乱序数列?那显然不可能,那是胡插。 不是插入乱序数列那就是插入有序数列嘛,非黑即白多好记的。 如何插入有序数列呢,给我的数列一般都是打乱的啊,我怎么判断哪里有序了。 其实答案就藏在身边
2017-10-07 18:48:28
397
原创 简单选择排序
选择排序顾名思义是选择,选择什么呢,选择的当前最小数的下标(数组)。 如果有长度为11的数组。0号位为哨兵位。从1号下标开始,1号位不管是什么数,我就先把1号位的数字1赋值给最小值下标minIndex,1号位这个位置永远是最小的(排完序后它对应的数字也应该是最小的),然后把最小值下标的数(当前下标为1)与余下的9个数依次比较,如果比较途中,有数字比1号位的数小,那么我就把那个比最小值下标要
2017-10-07 18:47:34
377
原创 冒泡排序
冒泡排序就如他的名字,每次都有泡泡浮上来,泡泡自然是最轻的,最小的,一次遍历数列侯最小的会交换到第一位(下标为1,下标0为哨兵位)。 其实也可以相反的来,每次遍历有最大的交换到最后一位,沉底法,就如石头沉到底一样。我用的就是沉底。用数组来举例,先是外层循环,设置i从1到 len-1,每次i++,从1开始因为0号下标为哨兵我们不管。至于为什么是len-1呢。因为我们知
2017-10-07 18:46:22
376
原创 八皇后及回溯算法
记着刚接触到八皇后的问题时,自己总是想不通如何使判断步骤退回来,自己套了好多个循环,最后还是这种情况 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 1
2017-10-07 18:41:04
518
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人