Just enjoy programming

#

linux RPC 测试(转载)

转自:
http://www.justwinit.cn/post/3960/


RPC是glibc提供的函数参数/返回值封装服务, 并将封装结果通过网络传到服务器.
RPC服务端首先要启动portmapper服务.
测试一个简单的RPC传输示例, 先定义一个模板文件test.x

program TESTPROG{
        version VERSION{
                int int_echo(int)=1;
                int get_str_len(string)=2;
                int add ( int, int ) = 3;
        }=1;
}=30000;
内含3个函数, 注意其中一个有2个参数.
然后可以用rpcgen生成一个Makefile:

rpcgen -a -N test.x

这会生成Makefile, 客户端和服务端的程序, 和函数示例.
我们手工修改一下Makefile

# This is a template Makefile generated by rpcgen
# Parameters
CLIENT = test_client
SERVER = test_server
SOURCES_CLNT.c =
SOURCES_CLNT.h =
SOURCES_SVC.c =
SOURCES_SVC.h =
SOURCES.x = test.x
TARGETS_SVC.c = test_svc.c test_server.c test_xdr.c
TARGETS_CLNT.c = test_clnt.c test_client.c test_xdr.c
TARGETS = test.h test_xdr.c test_clnt.c test_svc.c
OBJECTS_CLNT = $(SOURCES_CLNT.c:%.c=%.o) $(TARGETS_CLNT.c:%.c=%.o)
OBJECTS_SVC = $(SOURCES_SVC.c:%.c=%.o) $(TARGETS_SVC.c:%.c=%.o)
# Compiler flags
CFLAGS += -g -pipe
LDLIBS += -lnsl
RPCGENFLAGS = -N
# Targets
all : $(CLIENT) $(SERVER)
$(TARGETS) : $(SOURCES.x)
        rpcgen $(RPCGENFLAGS) $(SOURCES.x)
$(OBJECTS_CLNT) : $(SOURCES_CLNT.c) $(SOURCES_CLNT.h) $(TARGETS_CLNT.c)
$(OBJECTS_SVC) : $(SOURCES_SVC.c) $(SOURCES_SVC.h) $(TARGETS_SVC.c)
$(CLIENT) : $(OBJECTS_CLNT)
        $(LINK.c) -o $(CLIENT) $(OBJECTS_CLNT) $(LDLIBS)
$(SERVER) : $(OBJECTS_SVC)
        $(LINK.c) -o $(SERVER) $(OBJECTS_SVC) $(LDLIBS)
clean:
         $(RM) core $(TARGETS) $(OBJECTS_CLNT) $(OBJECTS_SVC) $(CLIENT) $(SERVER)

修改test_server.c服务端的处理函数, 提供3种服务:

/*
* This is sample code generated by rpcgen.
* These are only templates and you can use them
* as a guideline for developing your own functions.
*/
#include "test.h"
int *
int_echo_1_svc(int arg1,  struct svc_req *rqstp)
{
        static int  result;
        //echo.
        result=arg1;
        printf("[RPC1] source=%d, echo=%d\n", arg1, result);
        return &result;
}
int *
get_str_len_1_svc(char *arg1,  struct svc_req *rqstp)
{
        static int  result;
        //get strlen.
        result=strlen(arg1);
        printf("[PRC2] str=%s, len=%d\n", arg1, result);
        return &result;
}
int *
add_1_svc(int arg1, int arg2,  struct svc_req *rqstp)
{
        static int  result;
        result=arg1+arg2;
        printf("[RPC3] %d+%d=%d\n", arg1, arg2, result);
        return &result;
}

客户端test_client.c, 调用这三种服务:

/*
* This is sample code generated by rpcgen.
* These are only templates and you can use them
* as a guideline for developing your own functions.
*/
#include "test.h"
void
testprog_1(char *host)
{
        CLIENT *clnt;
        int  *result_1;
        int int_echo_1_arg1=55;
        int  *result_2;
        char *get_str_len_1_arg1="Hello, world";
        int  *result_3;
        int add_1_arg1=10;
        int add_1_arg2=20;
        clnt = clnt_create (host, TESTPROG, VERSION, "udp");
        if (clnt == NULL) {
                clnt_pcreateerror (host);
                exit (1);
        }
        result_1 = int_echo_1(int_echo_1_arg1, clnt);
        if (result_1 == (int *) NULL) {
                clnt_perror (clnt, "call failed");
        }
        else
                printf("[PRC1] echo %d, source %d\n", *result_1,
                        int_echo_1_arg1);
        result_2 = get_str_len_1(get_str_len_1_arg1, clnt);
        if (result_2 == (int *) NULL) {
                clnt_perror (clnt, "call failed");
        }
        else
                printf("[RPC2] return %d, should %d\n", *result_2,
                        strlen(get_str_len_1_arg1));
        result_3 = add_1(add_1_arg1, add_1_arg2, clnt);
        if (result_3 == (int *) NULL) {
                clnt_perror (clnt, "call failed");
        }
        else
                printf("[PRC3] %d+%d=%d\n", add_1_arg1, add_1_arg2,
                        *result_3);
        clnt_destroy (clnt);
}
OK, 可以调用make了.
生成可执行程序test_server和test_client.
我们启动./test_server, 用rpcinfo看看:

$rpcinfo -p 127.0.0.1
program vers proto port
100000 2 tcp 111 portmapper
30000 1 udp 36307
30000 1 tcp 34883
Bingo! 启动成功.

再开个终端, 尝试一下调用.

./test_client 127.0.0.1
[PRC1] echo 55, source 55
[RPC2] return 12, should 12
[PRC3] 10+20=30

正是我们期望的.

Add By:Jackxiang
make -f Makefile.test

posted @ 2011-08-07 16:44 周强 阅读(1151) | 评论 (0)编辑 收藏

最近的我

   最近的我状态不错,睡眠也好了很多,每天7点半左右起床,每天看看资料,看看论文,编编程序,晚上10点半左右回到宿舍,洗个澡上上网就睡觉了,周末去图书馆看看书或者实验室待着。这样的生活挺好的,就是现在每天坐车有点累。现在的心态确实不错,不再多想了,不再去想以后会去哪,以后该做什么,一切都随缘吧,每天都尽量努力点,把能做的事给做好。
   最近的动车相撞确实挺让人纠心的。单就技术方面我感觉我们的高铁和动车还是有很大问题的,有点大跃进,买国外的技术然后自己改装下,就说是处于世界领先水平了。技术的创新是需要长时间的积累的,我感觉我们目前最多只是个模仿者,更别谈创新了。我感觉很多方面我们是缺少创新的,单就计算机方面,国内最近炒得很热的云计算,好像很多公司都在搞,看上去很创新,但我感觉是缺乏技术积累的,很多公司目前只是在用国外的开源软件做做研究,到目前为止都没有一个像亚马逊,谷歌一样的数据中心。

posted @ 2011-07-31 20:18 周强 阅读(259) | 评论 (3)编辑 收藏

Nginx源码分析-Epoll模块(转载)

转载自:http://www.tbdata.org/archives/1296


Nginx源码分析-Epoll模块

3 comments 十二月 26th, 2010 | by yixiao in 高性能服务器

Linux平台上,Nginx使用epoll完成事件驱动,实现高并发;本文将不对epoll本身进行介绍(网上一堆一堆的文章介绍epoll的原理及使用方法,甚至源码分析等),仅看一下Nginx是如何使用epoll的。

Nginx在epoll模块中定义了好几个函数,这些函数基本都是作为回调注册到事件抽象层的对应接口上,从而实现了事件驱动的具体化,我们看如下的一段代码:

ngx_event_module_t  ngx_epoll_module_ctx = {
    &epoll_name,
    ngx_epoll_create_conf,               /* create configuration */
    ngx_epoll_init_conf,                 /* init configuration */
    {
        ngx_epoll_add_event,             /* add an event */
        ngx_epoll_del_event,             /* delete an event */
        ngx_epoll_add_event,             /* enable an event */
        ngx_epoll_del_event,             /* disable an event */
        ngx_epoll_add_connection,        /* add an connection */
        ngx_epoll_del_connection,        /* delete an connection */
        NULL,                            /* process the changes */
        ngx_epoll_process_events,        /* process the events */
        ngx_epoll_init,                  /* init the events */
        ngx_epoll_done,                  /* done the events */
    }
};


这段代码就是epoll的相关函数注册到事件抽象层,这里所谓的事件抽象层在前面的博文中有提过,就是Nginx为了方便支持和开发具体的I/O模型,从而实现的一层抽象。代码后面的注释将功能说明得很详细了,本文就只重点关注ngx_epoll_init和ngx_epoll_process_events两个函数,其他几个函数就暂且忽略了。

ngx_epoll_init主要是完成epoll的相关初始化工作,代码分析如下:

static ngx_int_t
ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
{
    ngx_epoll_conf_t  *epcf;
	/*取得epoll模块的配置结构*/
    epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module);
	/*ep是epoll模块定义的一个全局变量,初始化为-1*/
    if (ep == -1) {
    	/*创一个epoll对象,容量为总连接数的一半*/
        ep = epoll_create(cycle->connection_n / 2);
        if (ep == -1) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                          "epoll_create() failed");
            return NGX_ERROR;
        }
    }
	/*nevents也是epoll模块定义的一个全局变量,初始化为0*/
    if (nevents events) {
        if (event_list) {
            ngx_free(event_list);
        }

		/*event_list存储产生事件的数组*/
        event_list = ngx_alloc(sizeof(struct epoll_event) * epcf->events,
                               cycle->log);
        if (event_list == NULL) {
            return NGX_ERROR;
        }
    }
    nevents = epcf->events;
	/*初始化全局变量ngx_io, ngx_os_is定义为:
		ngx_os_io_t ngx_os_io = {
    		ngx_unix_recv,
    		ngx_readv_chain,
    		ngx_udp_unix_recv,
    		ngx_unix_send,
    		ngx_writev_chain,
    		0
		};(位于src/os/unix/ngx_posix_init.c)
	*/
    ngx_io = ngx_os_io;
	/*这里就是将epoll的具体接口函数注册到事件抽象层接口ngx_event_actions上。
	具体是上文提到的ngx_epoll_module_ctx中封装的如下几个函数
        ngx_epoll_add_event,
        ngx_epoll_del_event,
        ngx_epoll_add_event,
        ngx_epoll_del_event,
        ngx_epoll_add_connection,
        ngx_epoll_del_connection,
        ngx_epoll_process_events,
        ngx_epoll_init,
        ngx_epoll_done,
	*/
    ngx_event_actions = ngx_epoll_module_ctx.actions;
#if (NGX_HAVE_CLEAR_EVENT)
	/*epoll将添加这个标志,主要为了实现边缘触发*/
    ngx_event_flags = NGX_USE_CLEAR_EVENT
#else
	/*水平触发*/
    ngx_event_flags = NGX_USE_LEVEL_EVENT
#endif
                      |NGX_USE_GREEDY_EVENT /*io的时候,直到EAGAIN为止*/
                      |NGX_USE_EPOLL_EVENT; /*epoll标志*/
    return NGX_OK;
}

epoll初始化工作没有想象中的复杂,和我们平时使用epoll都一样,下面看ngx_epoll_process_events,这个函数主要用来完成事件的等待并处理。

static ngx_int_t
ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{
    int                events;
    uint32_t           revents;
    ngx_int_t          instance, i;
    ngx_uint_t         level;
    ngx_err_t          err;
    ngx_log_t         *log;
    ngx_event_t       *rev, *wev, **queue;
    ngx_connection_t  *c;
	/*一开始就是等待事件,最长等待时间为timer;nginx为事件
	专门用红黑树维护了一个计时器。后续对这个timer单独分析。
	*/
    events = epoll_wait(ep, event_list, (int) nevents, timer);
    if (events == -1) {
        err = ngx_errno;
    } else {
        err = 0;
    }
    if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
        /*执行一次时间更新, nginx将时间缓存到了一组全局变量中,方便程序高效的获取事件。*/
        ngx_time_update();
    }
	/*处理wait错误*/
    if (err) {
        if (err == NGX_EINTR) {
            if (ngx_event_timer_alarm) {
                ngx_event_timer_alarm = 0;
                return NGX_OK;
            }
            level = NGX_LOG_INFO;
        } else {
            level = NGX_LOG_ALERT;
        }
        ngx_log_error(level, cycle->log, err, "epoll_wait() failed");
        return NGX_ERROR;
    }
	/*wait返回事件数0,可能是timeout返回,也可能是非timeout返回;非timeout返回则是error*/
    if (events == 0) {
        if (timer != NGX_TIMER_INFINITE) {
            return NGX_OK;
        }
        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                      "epoll_wait() returned no events without timeout");
        return NGX_ERROR;
    }
    log = cycle->log;
	/*for循环开始处理收到的所有事件*/
    for (i = 0; i read;
		。。。。。。。。。。。。。

		/*取得发生一个事件*/
        revents = event_list[i].events;

		/*记录wait的错误返回状态*/
        if (revents & (EPOLLERR|EPOLLHUP)) {
            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0,
                           "epoll_wait() error on fd:%d ev:%04XD",
                           c->fd, revents);
        }
        if ((revents & (EPOLLERR|EPOLLHUP))
             && (revents & (EPOLLIN|EPOLLOUT)) == 0)
        {
            /*
             * if the error events were returned without EPOLLIN or EPOLLOUT,
             * then add these flags to handle the events at least in one
             * active handler
             */
            revents |= EPOLLIN|EPOLLOUT;
        }
		/*该事件是一个读事件,并该连接上注册的读事件是active的*/
        if ((revents & EPOLLIN) && rev->active) {
            if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
                rev->posted_ready = 1;
            } else {
                rev->ready = 1;
            }

			/*事件放入相应的队列中;关于此处的先入队再处理,在前面的文章中已经介绍过了。*/
            if (flags & NGX_POST_EVENTS) {
                queue = (ngx_event_t **) (rev->accept ?
                               &ngx_posted_accept_events : &ngx_posted_events);
                ngx_locked_post_event(rev, queue); /*入队*/
            } else {
                rev->handler(rev);
            }
        }
        wev = c->write;
		/*发生的是一个写事件,和读事件完全一样的逻辑过程*/
        if ((revents & EPOLLOUT) && wev->active) {
            if (flags & NGX_POST_THREAD_EVENTS) {
                wev->posted_ready = 1;
            } else {
                wev->ready = 1;
            }
			/*先入队再处理*/
            if (flags & NGX_POST_EVENTS) {
                ngx_locked_post_event(wev, &ngx_posted_events);
            } else {
                wev->handler(wev);
            }
        }
    }
    return NGX_OK;
}

本文将关注的两个epoll函数也就这么一点代码了,但整个epoll还有添加事件和删除事件等的相关函数,代码都很简单,本文就不做具体的分析了。

posted @ 2011-07-10 00:54 周强 阅读(915) | 评论 (0)编辑 收藏

linux 进程间通信之消息传递

linux 进程间通信中消息传递主要分为管道,FIFO,消息队列
(1)管道
管道由pipe函数创建,提供一个单路(单向)数据流。pipe函数返回两个文件描述符:fd[0]和fd[1]。前者打开来读,后者打开来写。管道没有名字,所以只能由有亲缘关系的进程使用。尽管管道是由单个进程创建的,它却很少在单个进程内使用。管道的典型用途为两个不同进程(一个是父进程,一个是子进程)提供进程间的通信手段。首先,由一个进程(它将成为父进程)创建一个管道后调用fork派生一个自身的副本。接着,父进程关闭这个管道的读出端,子进程关闭同一管道的写入端。或者父进程关闭这个管道的写入端,子进程关闭同一管道的读出端。这就在父子进程间提供了一个单向数据流。

(2)FIFO
FIFO指代先进先出(First in,First out),linux中的FIFO类似管道。它是一个单向(半双工)数据流。不同于管道的是,每个FIFO有一个路径名与之关联,从而允许无亲缘关系的进程访问同一个FIFO。FIFO也称为有名管道。FIFO由mkfifo函数创建。其中pathname是一个普通的Unix路径名,它是该FIFO的名字。mkfifo 函数已隐含指定 O_CREAT|O_EXCL. 也就是说,它那么创建一个新的FIFO,要么返回一个EEXIST错误(如果所指定的名字的FIFO已经存在)。如果不想希望创建一个新的FIFO,那就改为调用open而不是mkfifo.要打开一个已存在的FIFO或创建一个新的FIFO,应先调用mkfifo,再检查它是否返回EEXIST错误,若返回该错误则改为调用open.mkfifo 命令也能创建FIFO。可以从shell脚本或命令行中使用它。在创建出一个FIFO后,它必须或者打开来读,或者打开来写,所用的可以是open函数,也可以是某个标准I/O打开函数。FIFO不能打开来既读又写,因为它是半双工的。对管道或FIFO的write总是往末尾添加数据,对它们的read则总是从开头返回数据。如果对管道或FIFO调用lseek,那就返回ESPIPE错误。

(3)Posix 消息队列
消息队列可认为是一个消息链表。有足够写权限的线程可往队列中放置消息,有足够读权限的线程可从队列中取走消息。每个消息都是一个记录,它由发送者赋予一个优先级。在某个进程往一个队列写入消息之前,并不需要另外某个进程在该队列上等待消息的到达。这跟管道和FIFO是相反的,对后者来说,除非读出者已存在,否则先有写入者是没有意义的。一个进程可以往某个队列写入一些消息,然后终止,再让另外一个进程在以后某个时刻读出这些消息。消息队列具有随内核的持续性,这跟管道和FIFO不一样。Posix消息队列和System V消息队列。这两组函数间存在许多相似性,但也有主要的区别
1. 对Posix消息队列的读总是返回最高优先级的最早消息,对System V消息队列的读则可以返回任意指定优先级的消息。
2.当往一个空队列放置一个消息时,Posix 消息队列允许产生一个信号或启动一个线程。System V消息队列则不提供类似机制。

队列中的每个消息具有如下属性:
1.一个无符号整数优先级(Posix)或一个长整数类型(System V).
2.消息的数据部分长度(可以为0).
3.数据本身(如果长度大于0)

函数接口
1. mqd_t mq_open(const char *name,int oflag,...)
mq_open函数创建一个新的消息队列或打开一个已存在的消息队列
2.int mq_close(mqd_t mqdes);
mq_close函数关闭一个消息队列。
3.int mq_unlink(const char *name);
从系统中删除用作第一个参数的某个name.
4. int mq_getattr(mqd_t mqdes,struct mq_attr *attr);
   int mq_setattr(mqd_t mqdes,const struct mq_attr *attr,struct mq_attr *oattr);
每个消息队列有四个属性,mq_getattr返回所有这些属性,mq_setattr则设置其中某个属性。
struct mq_attr{
   long mq_flags;
   long mq_maxmsg;
   long mq_msgsize;
   long mq_curmsgs;
};
5.int mq_send(mqd_t mqdes,const char *ptr,size_t len,unsigned int prio);
 int mq_receive(mqd_t mqdes,char *ptr,size_t len,unsigned int *priop);
mq_send函数往消息队列中写入消息,mq_receive函数从消息队列中读出消息。

6.int mq_notify(mqd_t mqdes,const struct sigevent *motification);
结构体:
union sigval{
    int sival_int;
    void *sival_ptr;
};

struct sigevent
{
    int sigev_notify;
    int sigev_signo;
    union sigval sigev_value;
    void  (*sigev_notify_function)(union sigval);
    pthread_attr_t *sigev_notify_attributes;
};
mq_notify函数为指定队列建立或删除异步事件通知。一些普遍适用于该函数的若干规则
1).如果notification参数非空,那么当前进程希望在一个消息达到所指定的先前为空的队列时得到通知。我们说"该进程被注册为接收该队列的通知"。
2).如果notification参数为空指针,而且当前进程目前被注册为接收所指定队列的通知,那么已存在的注册将被撤销。
3).任意时刻只有一个进程可以被注册为接收某个给定队列的通知。
4).当有一个消息达到某个先前为空的队列,而且已有一个进程被注册为接收该队列的通知时,只有在没有任何线程阻塞在该队列的mq_receive调用中的前提下,通知才会发出。这就是说,在mq_receive调用中的阻塞比任何通知的注册都优先。
5).当该通知被发送给它的注册进程时,其注册即被撤销。该进程必须再次调用mq_notify以重新注册(想要的话)。

参考:Unix进程间通信

posted @ 2011-07-07 02:29 周强 阅读(3016) | 评论 (3)编辑 收藏

近期计划

     最近的思绪有点乱,离找工作只剩7,8,9三个月了,该是好好计划下。
 (1)尽快把论文写完
 (2)找工作前要要看完的书
unix三卷书(就剩unix进程间通信),TCP/IP 详解(卷一),c++编程思想2卷书,effective c++,STL源码分析,设计模式,算法导论,编程之美,程序员面试宝典
(3)源码阅读  nginx 阅读

posted @ 2011-07-06 12:37 周强 阅读(316) | 评论 (4)编辑 收藏

     晚上独自一个人走在校园里,感觉特别的安静,我喜欢这种平静的生活,可能是因为这么多年一个人习惯了,有时候更喜欢一个人静静地待着,不用去理会其他人,可以独自地思考。我感觉我以前缺少一个勇敢的心,不敢去追求一些美好的事物,错过了很多东西。很多事是没有对错的,只在于自己的选择。既然是自己做的选择就不应该去后悔什么,或许当初不这样选择我会变得更好,但至少现在的我应该感谢当初的选择,因为当初的选择才有现在的自己。突然想到了大姐说的一个词“自律”,我感觉我有时真得太过自律了,有时候真想去放纵自己,羡慕那些把人生当游戏的人,人生得意须尽欢,但我却做不到,因为我知道我身上有很多责任,有很多事情需要去做。
    上周打家里电话,我爸问我是不是要放暑假了,我能听出来他们想让我回家看看了,我也很想回家看看,但最近我真得很忙,估计是没时间回去了,只能等到过年的时候再回去了。
    上周末去医院,发现有些数字确实有点高了,可能是因为长时间的压力与睡眠不好造成的,是时候该为自己减减压了,现在想想我真有点杞人忧天,很多事情我都可以不去想的。现在开始要坚持跑步锻炼身体,好好改善睡眠了。要学会平静地面对一切,简单点,淡定点,不是非要做的事就不去想了,船到桥头自然直。
   

posted @ 2011-07-04 21:38 周强 阅读(262) | 评论 (2)编辑 收藏

linux 进程间通信综述

linux进程间通信主要分为以下4个领域
(1)消息传递(管道,FIFO,消息队列)
(2)同步(互斥锁,条件变量,读写锁,信号量)
(3)共享内存区(匿名共享内存区,有名共享内存区)
(4)过程调用(Solaris门,Sun RPC)


linux进程间的信息共享可以分为
(1) 基于文件系统的共享
(2) 基于内核的共享
(3) 基于共享内存区的共享


IPC对象的持续性
(1)随进程间持续的IPC对象一直存在到打开着该对象的最后一个进程关闭该对象的最后一个进程关闭该对象为止。
(2)随内核持续的IPC对象一直存在到内核重新自举或显式删除该对象为止。
(3)随文件系统持续的IPC对象一直存在到显示删除该对象为止。即使系统自举了,该对象还是存在的。


IPC类型                                       持续性
管道                                           随进程
FIFO                                          随进程

Posix互斥锁                                 随进程
Posix条件变量                              随进程
Posix读写锁                                 随进程
fcntl记录上锁                                随进程

Posix消息队列                              随内核
Posix有名信号量                           随内核
Posix基于内存的信号量                   随进程
Posix共享内存区                           随内核

System V消息队列                        随内核
System V信号量                           随内核
System V共享内存区                     随内核

TCP套接字                                  随进程
UDP套接字                                  随进程
Unix域套接字                               随进程






名字空间:
当两个或多个无亲缘关系的进程使用某种类型的IPC对象来彼此交换信息时,该IPC对象必须有一个某种形式的名字或者标识符,这样其中一个进程(往往是服务器)可以创建该IPC对象,其余进程则可以指定同一个IPC对象。

IPC类型                        用于打开或创建IPC的名字空间                IPC打开后的标识
管道                                     没有名字                                      描述符
FIFO                                    路径名                                         描述符

Posix互斥锁                          没有名字                                      pthread_mutex_t指针
Posix条件变量                       没有名字                                      pthread_cond_t指针
Posix读写锁                          没有名字                                      pthread_rwlock_t指针
fcntl记录上锁                        路径名                                         描述符

Posix消息队列                       Posix IPC名字                              mqd_t值
Posix有名信号量                    Posix IPC名字                              sem_t指针
Posix基于内存的信号量            没有名字                                     sem_t指针
Posix共享内存区                    Posix IPC名字                              描述符


System V消息队列                key_t键                                       System V IPC标识符
System V 信号量                  key_t键                                       System V IPC标识符
System V共享内存区              key_t键                                      System V IPC 标识符

门                                      路径名                                         描述符
sun RPC                             程序/版本                                     RPC句柄

TCP套接字                            IP地址与TCP 端口                         描述符
UDP套接字                           IP地址与UDP端口                          描述符
Unix域套接字                        路径名                                        描述符  

posted @ 2011-07-04 09:58 周强 阅读(10862) | 评论 (3)编辑 收藏

   最近一直在下雨,有好几次都被淋湿了,不过想想偶尔淋淋雨感觉也挺好的。我还是挺喜欢下雨的,可能跟我的性格有点关系,眼神中总有一丝的忧愁。记得小时候下雨的时候总喜欢坐在家门口的傻傻地看着雨。雨总能给我带来一种安静的感觉,下雨天在实验室看看书对于我来说可以算是一种享受,可以不去想一些烦心事,可以让我浮躁的心静下来。高中有空闲下来的时候喜欢读会诗,雨巷是其中一首比较喜欢的诗。

雨巷

作者: 戴望舒

 
撑着油纸伞,独自
彷徨在悠长、悠长
又寂寥的雨巷
我希望逢着
一个丁香一样地
结着愁怨的姑娘
 
她是有
丁香一样的颜色
丁香一样的芬芳
丁香一样的忧愁
在雨中哀怨
哀怨又彷徨
 
她彷徨在这寂寥的雨巷
撑着油纸伞
像我一样
像我一样地
默默彳亍着
寒漠、凄清,又惆怅
 
她默默地走近
走近,又投出
太息一般的眼光
她飘过
像梦一般地
像梦一般地凄婉迷茫
 
像梦中飘过
一枝丁香地
我身旁飘过这女郎
她静默地远了、远了
到了颓圮的篱墙
走尽这雨巷
 
在雨的哀曲里
消了她的颜色
散了她的芬芳
消散了,甚至她的
太息般的眼光
丁香般的惆怅
 
撑着油纸伞,独自
彷徨在悠长、悠长
又寂寥的雨巷
我希望飘过
一个丁香一样地
结着愁怨的姑娘


posted @ 2011-06-30 17:12 周强 阅读(304) | 评论 (5)编辑 收藏

linux 守护进程编写规则

linux 守护进程编写规则

(1)首先要做的是调用umask将文件模式创建屏蔽字设置为0.由继承得来的文件模式创建屏蔽字可能会拒绝设置某些权限。
(2)调用fork,然后使父进程退出(exit).这样做实现了下面几点:第一,如果该守护进程是作为一条简单shell命令启动的,那么父进程终止使得shell认为这条命令已经执行完毕。第二,子进程继承了父进程的进程组ID,但具有一个新的进程ID,这就保证了子进程不是一个进程组的组长进程。这对于下面就要做的setsid调用是必要的前提条件。
(3)调用setsid以创建一个新会话,是调用进程:(a)成为新会话的首进程,(b)成为一个新进程组的组长进程,(c)没有控制终端。在有些人建议在此时再次调用 fork,并是父进程终止。第二个子进程作为守护进程继续运行。这样就保证了该守护进程不是会话首进程。
(4)将当前工作目录更改为根目录。
(5)关闭不再需要的文件描述符。这使守护进程不再持有从其父进程继承来的某些文件描述符。
(6)某些守护进程打开/dev/null使其具有文件描述符0,1,2.这样,任何一个试图读标准输入,写标准输出或标准出错的库例程都不会产生任何效果。

参考:UNIX环境高级编程

posted @ 2011-06-29 21:50 周强 阅读(2161) | 评论 (1)编辑 收藏

nginx源码分析 ngx_palloc.h ngx_palloc.c

ngx_palloc.h 和 ngx_palloc.c主要用于nginx管理内存池

#include <ngx_config.h>
#include <ngx_core.h>


/*
 * NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86.
 * On Windows NT it decreases a number of locked pages in a kernel.
 */
#define NGX_MAX_ALLOC_FROM_POOL  (ngx_pagesize - 1)
//内存池默认大小
#define NGX_DEFAULT_POOL_SIZE    (16 * 1024)

//#define ngx_align(d, a)     (((d) + (a - 1)) & ~(a - 1)) 将d向上取a的倍数。

#define NGX_POOL_ALIGNMENT       16
//内存池的最小大小,为16的倍数
#define NGX_MIN_POOL_SIZE                                                     \
    ngx_align((sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)),            \
              NGX_POOL_ALIGNMENT)

//ngx_pool_cleanup_pt 为函数指针
typedef void (*ngx_pool_cleanup_pt)(void *data);

typedef struct ngx_pool_cleanup_s  ngx_pool_cleanup_t;
//这个结构用来表示内存池中的数据的清理handler
//handler表示清理函数,data表示传递给清理函数的数据,next表示下一个清理handler,
//也就是说当destroy这个pool的时候会遍历清理handler链表,然后调用handler.
struct ngx_pool_cleanup_s {
    ngx_pool_cleanup_pt   handler;
    void                 *data;
    ngx_pool_cleanup_t   *next;
};


typedef struct ngx_pool_large_s  ngx_pool_large_t;
//该结构表示大块内存,这个结构很简单,就是一个指针指向下一块large,一个alloc指向数据
struct ngx_pool_large_s {
    ngx_pool_large_t     *next;
    void                 *alloc;
};

//数据区的指针ngx_pool_data_t。其中last表示当前的数据区的已经使用的数据的结尾。
//end表示当前的内存池的结尾。也就是说end-last就是内存池未使用的大小。
typedef struct {
    u_char               *last;
    u_char               *end;
//指向下一块内存池
    ngx_pool_t           *next;
//申请该内存池失败的标记
    ngx_uint_t            failed;
} ngx_pool_data_t;


struct ngx_pool_s {
    ngx_pool_data_t       d;
    size_t                max;
    ngx_pool_t           *current;
    ngx_chain_t          *chain;
    ngx_pool_large_t     *large;
    ngx_pool_cleanup_t   *cleanup;
    ngx_log_t            *log;
};


typedef struct {
    ngx_fd_t              fd;
    u_char               *name;
    ngx_log_t            *log;
} ngx_pool_cleanup_file_t;


void *ngx_alloc(size_t size, ngx_log_t *log);
void *ngx_calloc(size_t size, ngx_log_t *log);

ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log);
void ngx_destroy_pool(ngx_pool_t *pool);
void ngx_reset_pool(ngx_pool_t *pool);

void *ngx_palloc(ngx_pool_t *pool, size_t size);
void *ngx_pnalloc(ngx_pool_t *pool, size_t size);
void *ngx_pcalloc(ngx_pool_t *pool, size_t size);
void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);
ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);


ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);
void ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd);
void ngx_pool_cleanup_file(void *data);
void ngx_pool_delete_file(void *data);


#endif /* _NGX_PALLOC_H_INCLUDED_ */

posted @ 2011-06-16 18:12 周强 阅读(461) | 评论 (0)编辑 收藏

仅列出标题
共6页: 1 2 3 4 5 6