服务器编程基本框架: 事件处理模式 一般来说,IO复用机制都需要一个事件分离器,它会将事件源分发给对应的处理者,即将那些读写事件源分发给各读写事件处理者。Reactor和Proactor就是两种最常用的事件处理模式。 Reactor Reactor模式是指主线程只负责监听文件描述符上是不是有事件发生,有的话就将该事件通知工作线程,除此之外,主线程不需要做其他任何工作,其他的数据读写、逻辑处理等都是在工作线程中完成的。比如说在Reactor模式下的读操作过程: - 在主线程上注册读就绪事件和相应的事件处理器- 事件分离器等待事件- 事件到来,激活分离器,分离器调用事件对应的工作线程。- 工作线程完成实际的读操作,处理读到的数据,注册新的事件,然后返还控制权。 Proactor Proactor模式与Reactor一样,都是对某个IO事件进行通知,不同的是,Proactor模式中主线程不止监听文件描述符上的事件是否发生,还要完成所有的读写操作,而工作线程要做的只是处理逻辑问题。也就是说,Proac 继续阅读 >>


宋润雨 15/03/31 18:08:57
这篇文章是下篇,所以如果你对TCP不熟悉的话,还请你先看看上篇《TCP的那些事儿(上)》 上篇中,我们介绍了TCP的协议头、状态机、数据重传中的东西。但是TCP要解决一个很大的事,那就是要在一个网络根据不同的情况来动态调整自己的发包的速度,小则让自己的连接更稳定,大则让整个网络更稳定。在你阅读下篇之前,你需要做好准备,本篇文章有好些算法和策略,可能会引发你的各种思考,让你的大脑分配很多内存和计算资源,所以,不适合在厕所中阅读。 TCP的RTT算法 从前面的TCP重传机制我们知道Timeout的设置对于重传非常重要。 设长了,重发就慢,丢了老半天才重发,没有效率,性能差;设短了,会导致可能并没有丢就重发。于是重发的就快,会增加网络拥塞,导致更多的超时,更多的超时导致更多的重发。 而且,这个超时时间在不同的网络的情况下,根本没有办法设置一个死的值。只能动态地设置。 为了动态地设置,TCP引入了RTT——Round Trip Time,也就是一个数据包从发出去到回来的时间。这样发送端就大约知道需要 继续阅读 >>


宋润雨 15/02/22 22:51:56
上篇中,主要向你介绍TCP协议的定义和丢包时的重传机制。下篇中,重点介绍TCP的流迭、拥塞处理。 首先,我们需要知道TCP在网络OSI的七层模型中的第四层——Transport层,IP在第三层——Network层,ARP在第二层——Data Link层,在第二层上的数据,我们叫Frame,在第三层上的数据叫Packet,第四层的数据叫Segment。 首先,我们需要知道,我们程序的数据首先会打到TCP的Segment中,然后TCP的Segment会打到IP的Packet中,然后再打到以太网Ethernet的Frame中,传到对端后,各个层解析自己的协议,然后把数据交给更高层的协议处理。 TCP头格式 接下来,我们来看一下TCP头的格式 TCP头格式(图片来源) 你需要注意这么几点: TCP的包是没有IP地址的,那是IP层上的事。但是有源端口和目标端口。一个TCP连接需要四个元组来表示是同一个连接(src_ip, src_port, dst_ip, dst_port)准确说是五元组,还有一 继续阅读 >>


宋润雨 15/02/22 22:47:50
            要想实现并发编程,最简单的模式就是1个进程/线程处理1个连接的全部生命周期,当我们使用默认的套接字时,它会将一个新的连接与一个进程或线程绑定,这样等待处理消息的进程或线程就会阻塞而等待消息准备好,在高并发下这会导致进程/线程频繁的睡眠、唤醒,从而影响了CPU的效率。而多路复用则是解决这一问题的“利器”,它可以同时监控所有的连接,它虽然也会进入睡眠等待阶段,但是这一个进程/线程是为所有连接而等待,只要有一个连接准备好了,我们的进程/线程就会被唤醒,这样就大大提高了效率。简单来说,多路复用首先需要构造一张描述符表,然后调用一个函数,直到这些描述符中的一个已准备好时,该函数才返回。 目前支持I/O复用的系统调用有:select、pselect、poll、epoll 1. select  select 函数原型如下: #include<sys/select.h> int select( int nfds, fd_set *restrict readfds, fd_set 继续阅读 >>


宋润雨 14/11/17 21:40:22
           我们都知道Linux下一个C程序的生成分为4个阶段:预编译(.i) --> 编译(.s) --> 汇编(.o) --> 链接(可执行文件) 在预处理阶段,它会修改原始的C程序,将源程序翻译成一个ASCII码的以.i结尾的中间文件。它会读取系统头文件stdio.h的内容,并把它直接插入到程序文本中。 在编译阶段,编译器将以.i为扩展名的文本文件翻译成以.s作为扩展名的文本文件,它包含一个汇编语言程序。 在汇编阶段,汇编器将以.s为扩展名的文本文件翻译成机器语言指令,将结果存在以.o为扩展名的二进制目标文件中。 在链接阶段,会将文件中调用的库函数合并到上一步生成的二进制目标文件中。比如若调用了printf函数,在链接阶段,它会存在于一个名为printf.o的单独预编译好的目标文件中,这个文件会与我们上一步的.o文件合并成一个文件,即上一步的生成的.o文件中,它是一个可执行目标文件,shell调用操作系统中一个叫做加载器的函数,它拷贝可执行文件中的代码和数据到内存, 继续阅读 >>


宋润雨 14/07/23 14:14:35
      最近(其实是半个月前)听了小组一位同学关于iptables的讲座,觉得很有意思,所以又结合观看了两节iptables的公开课的心得,写下这篇笔记。 一.什么是netfilter ,什么是iptables,? Linux内核中有关网络控制的功能,就是通过netfilter(网络过滤)模块实现的,常见的访问控制包括:哪些ip可以访问服务器、可以使用哪些协议、哪些接口,以及对数据包的处理等等,简单的说,网络访问控制,就是实现了类似防火墙的功能。在用户层,我们则使用iptables对netfilter进行控制管理。netfilter与iptables结合起来,共同完成了linux系统中防火墙的功能。 二.netfilter的基本概念 netfilter定义了两个基本概念:链(chain)和表(table)。其中,netfilter总共定义(或者可以说划分)了5个链: INPUT:输入到本机的数据; FORWARD:数据包经过本机转发的数据; OUTPUT 继续阅读 >>


宋润雨 14/05/07 20:04:07
       KMP是Knuth-Morris-Pratt的简称,KMP算法是模式匹配当中的经典算法,也就是某大神说的“以某些人的名字命名”的算法,它是由D.E.Knuth,J.H.Morris和V.R.Pratt共同提出的一个改进算法。和BF(Brute Force)算法相比,KMP算法的优点在于当主串中的i指针失配时,不需要回溯到上一次开始匹配的下一个位置,而是利用已经得到的next数组将模式串中的j指针移动到尽可能向后的位置后,然后继续比较。        举个例子,当主串S为“0000000000000000000000000000000000000001”,而要匹配的子串T为“0000000001”,如果用简单模式匹配算法,第一次匹配,直到i=j=10,发生失配,i要变为2,j要变为1,继续匹配,依次类推。每一次都是直到匹配到T串的最后一位,才会发现它们原来是不匹配的。                                                             继续阅读 >>


宋润雨 13/11/04 21:34:45
                                                          约瑟夫环问题是一道经典的数据结构的题目,问题描述为:编号为1,2,......,n的n个人按顺时针方向围坐在一张圆桌周围,每个人持有一个密码(正整数)。一开始任选一个正整数作为报数的上限值m,从第一个人开始按顺时针方向自1开始报数,报到m时停止报数,报到m的那个人出列,将他的密码作为新的m值,从他顺时针方向的下一个人开始重新从1报数,数到m的那个人又出列,如此下去,直至圆桌周围的人全部出列为止。            我选择用双向链表来存储每个人的信息,每个结点存储的内容有:name[20],password,flag(顺逆时针的标志)以及prior和next指针。 typedef struct person {      char name[20];      int password;      int flag;      struct person *prior, *nex 继续阅读 >>


宋润雨 13/10/15 20:12:06
              如何在linux下实现简单的FTP,这是我在这个暑假完成的最主要的学习任务。实现简单的服务器与客户端间的上传与下载功能,我们需要知道什么是c/s架构以及套接字。关于套接字socket,这篇博客里讲的很详细,链接奉上 http://blog.csdn.net/sim_szm/article/details/9569607#comments 那么什么又是c/s架构呢?Client和Server常常分别处在相距很远的两台计算机上,Client程序的任务是将用户的要求提交给Server程序,再将Server程序返回的结果以特定的形式显示给用户;Server程序的任务是接收客户程序提出的服务请求,进行相应的处理,再将结果返回给客户程序。                                     上图很清楚的画出了一个面向连接的c/s模型,中间需要用到针对socket的一些操作函数,还有read等文件函数。 接下来,就是我画的服务器端与客户端的流程图了。(画的比较 继续阅读 >>


宋润雨 13/09/03 20:37:51
                              linux c上说:使用条件变量主要包括两个动作:一个等待使用资源的线程等待“条件变量被设置为真”;                     另一个线程在使用完资源后“设置条件为真”,这样就可以保证线程间的同步了。这样就存在一个关键问题,                     就是要保证条件变量能被正确的修改,条件变量要受到特殊的保护,实际使用中互斥锁扮演者这样一个保护者                     的角色。                              由上面的一段话我们可以知道,互斥锁与条件变量是形影不离的好朋友。可是,他们到底是怎样合作的呢?                     我们来看一段代码。 #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <pthread.h> 继续阅读 >>


宋润雨 13/07/31 14:26:30