编写高效服务器程序,需考虑的因素?

简单的搜索查询了下资料,copy了一些idea:

服务器带宽 内存 硬盘大小
建立连接池
肯定要分布式 连接请求如何分配
进程、线程如何访问临界资源
如何判断客户端已经挂了
如何避免DNS攻击
地址映射

降低每个连接的内存占用量。
降低每个连接的CPU资源占用率。
主要用iocp epoll kqueue以及sendfile这些api。研究学习nginx源码。

关于fork的一道面试题

整理转自:coolshell,一道fork的面试

一道题目:

#include<stdio.h>

#include<unistd.h>

#include<wait.h>

#include<sys/types.h>

int main()

{

    for (int i =0; i < 2;i++)

{

                    fork ();

                   printf("-");

     } 

     wait(NULL);

     return 0;

}

如果对fork的机制比较熟悉的话,该问题并不难,会输出6个’-‘,但是运行一下会发现,很诡异地输出了个’-‘。

先来说说fork的系统调用:

  • fork系统调用事Unix下,自身进程创建子进程的系统调用函数,一次调用,返回两次结果,如果返回值pid_t pid = fork(),子进程返回0,父进程返回子进程的pid。
  • 还有一个比较重要大东西,在fork的调用处,父进程的进程空间,会原封不动的拷贝到子进程中(对,是完全的copy),包括:指令,变量的值,程序调用栈,环境变量,缓冲区。

所以上面的程序会输出8个’-‘,因为printf(“-“);语句有buff,对于上述程序,printf把’-‘放到了缓冲区,并没有输出。来我们举个🌰帮助理解:

int main()

{  

   printf("123");

 //  printf("123\n");

   sleep (3);

  return 0;

}

大家分别去执行下,两个代码就会发现,原来123开始的时候是在缓存区,并没有立即输出,而是在程序退出的那会才输出的。

我们继续:

所以在fork的时候,缓存区被复制到了子进程的的内存空间,所以就多了2个-。

 

20151112

下班回家,异常的感觉疲惫,倒头睡了一会,起来洗澡,逛了一圈coolshell,发现了一个好的博客:

Linus:为何对象引用计数必须是原子的

Linus大神又在rant了!这次的吐槽对象是时下很火热的并行技术(parellism),并直截了当地表示并行计算是浪费所有人时间(“The whole “let’s parallelize” thing is a huge waste of everybody’s time.”)。大致意思是说乱序性能快、提高缓存容量、降功耗

进而发现 冠诚关于并行技术的研究,很多当代技术。有干货看了。

聊聊指针

都说c语言的精华就是指针,内存管理了,但是指针对于很多人来说都是非常难的东西,今天就来聊聊各种指针。

  1. 先从简单的开始分析:

 

  • int p:这是一个普通的整型变量。
  • int *p:从变量名p开始,与*结合,所以p是一个指针,在结合前面的int,说明这是一个指向int类型的指针。
  • int p[n]:和之前一样从p变量开始,与[]结合,说明p是一个数组,在看前面 int,说明包含n个int类型整数的数组。
  • int *p[n]:同理,先结合[],因为优先级比*高,所以p是数组,在结合*说明数组里面的元素为指针类型,然后和int结合,说明指针所指向的内容的类型是整数,所以p是一个指向整型数据的指针组成的数组。
  • int (*p)[n]:首先从p开始因为大括号的存在,结合*,说明p是一个指针,然后与[]结合,说明指针指向的内容是一个数组,然后再与int结合,说明数组里的元素是整形的,所以p是一个指向由n个整数组成的数组的指针。(和上一个指针数组需要好好看一下)。
  • int **p:首先p先和第二个*结合,说明p是一个指针,然后再与第一个*结合,说明指针所指向的元素是指针(为了区分起个别名:第二个指针),然后再与int结合,说明第二个指针指向的元素是整型。(后面会有详细解释)
  • int p(int):从p开始,先与()结合,说明p是一个函数,括号里的int,说明p函数有一个参数,是int类型的。 最前面的int,大家肯定都知道了吧,对,那是返回值。
  • int (*p)(int):从p开始,与*结合,说明p是一个指针,在看(*p)这个括号,说明指针指向了的是一个函数,接着后面的(int),相信你们已经想到了。所以p是一个函数指针,函数的返回值为int,并且有一个int类型的参数。

来个变态的看看:int *(*p(int))[n]:本着找到变量名p右为先的原则(这是干货),以及优先级的原则我看到了p(int),对,这是一个函数p,包含一个int类型参数,接着*p(int),说明函数的返回值为一个指针,接着(*p(int))[n],说明返回的指针指向了一个数组,接着               *(*p(int))[n],说明数组里面的元素为指针类型,最后int*(*p(int))[n],就是指针指向的类型为int的意思了。所以,p是一个包含int参数函数,并且函数返回一个指向整形指针数组的指针。

我也晕了,先写这么多吧,做广播体操去了。

回来继续:


 

  • 指针的类型:把指针声明语句中的指针变量名字去掉就是。

比如:int *p 类型就是int *,char *p类型就是char *,int ** 类型就是int*。

  • 指针指向的类型:当我们通过指针来访问指向的内存地址的时候,指针指向的类型决定了编译器要把这块内存里的内容当作什么来处理(int,char..),把指针声明语句中的指针名字和名字右边的*去掉就是指针指向的类型了。

比如:int *p 指针指向的类型就是int,char*p指向的类型就是char,int**p指向的类型就是int*p,this all。

  • 指针的值(指针指向的内存地址):指针的值是指针本身存储的数值,这个值被编译器当作一个地址,而不是一个一般的数值。在32位操作系统中,所有类型的指针的值都是一个32位整数,因为32位程序里内存地址都是32位长,指针所指向的内存区就是从指针的值所代表的那个内存地址,长度为sizeof(类型)的一片区域。所以我们说指针的值是xx,就相当于说该指针指向了以xx为首地址的一片区域,反过来一样。

指针本身占据的内存区:指针本身占了多大的内存,只要用sizeof运算符计算下就ok。其实不管各种指针,sizeof的时候都是4,因为32位系统嘛。


 

指针的计算

 

 

2进制数字求1的个数

算法课程整理

求1的个数:

给定一个32位,2进制的unsigned int N,求N二进制中1的个数。

显然,该问题可以通过不断右移动N,并且判断当前数字最低位是否为1,直到整数为0,即可。平均情况需要16次移动,以及16次加法。

int CountOne (int n)

{

int num =0;

while(n ){

num += (n&1);

n>>=1;

return num;

}

}

思路二:

用N与N-1做位与,每次把最低位清0,即可;

int CountOne(int n)

{

int num = 0;

while (n){

n &= (n-1);

num++;

}

}

 

20151106记

2015年的第一场雪,比以往时候来的还真的更早些,真的是冻死人了,本着晚上睡不好,上午迷糊的状态coding了一上午,测试一下午代码,盼星星盼月亮,盼到了下班,哈哈,明天周六啦,晚上参考《编程之法》写了一篇字符串旋转的算法,感觉算法真的是烧脑子啊,卢老板的一条微信,瞬间还是很开心:我四天没花钱了,不舒服,明天请你吃饭。加上老王的微信:我这里还有一瓶红酒,我妈从东北带的野生蘑菇,明天中午来搞一顿。多么感人的言语,多么温馨的基友情。多么好的人啊,哈哈,洗澡,睡觉。