end#define的用法BUF_SIZE256

linux C socket编程 (4)_linux c socket编程_词汇网
linux C socket编程 (4)
责任编辑:词汇网 发表时间: 5:41:15
多路复用I/O模型的服务器端:1.使用select实现。2.带有超时管理。3.有效的防止资源耗尽型攻击,很大程度上的防止挂起型攻击,但是由于不是非阻塞试的I/O,有可能在写客户端时,被挂起(select()被唤醒,但是要写的数据大于可用的写缓冲区大小,而这个时候客户端不再读取数据,这时服务器会被挂起,不再进入循环)。4.服务器超过最大承载客户端时,服务器不再接受新的客户端连接,客户端被阻塞于connect()操作,服务器不受影响。当某个客户端超时,或结束时,服务器可以继续接受新的客户端。 标签:
代码片段(5)[全屏查看所有代码] 1.[代码]多路复用I/O模型的服务器 #include "unp.h"#define CLT_NUMS 20#define RCV_BUF_SIZE 4096#define TIMEOUTS 10typedef struct s_info s_info_t;typedef int (*callback_f)(s_info_t *arg,fd_set *rd,fd_set *wr);int write_msg(s_info_t *arg,fd_set *rd,fd_set *wr);int read_msg(s_info_t *arg,fd_set *rd,fd_set *wr);struct s_info{ // callback_ char buf[RCV_BUF_SIZE]; size_ time_};int read_msg(s_info_t *arg,fd_set *rd,fd_set *wr){ char buf[BUF_ERR_SIZE]; assert(arg && rd && wr);__again: arg->len=read(arg->fd,arg->buf,sizeof(arg->buf)); arg->tm=time(0); FD_CLR(arg->fd,rd); if(arg->len>0){ arg->callback=write_ FD_SET(arg->fd,wr); //设置发送水平位的大小,也是使select()下次唤醒的条件,linux下始终为1,不会改变。 //setsock_normalopt_int(arg->fd,SO_SNDLOWAT,arg->len); return 1; } if(arg->len==-1){ if(errno==EINTR) goto __ fprintf(stderr,"client %d error:%s\n",arg->fd,geterr_str(errno,buf,sizeof(buf))); } else fprintf(stderr,"client %d end\n",arg->fd); close(arg->fd); arg->fd=-1; //if(!FD_ISSET(fd,rd))FD_SET(fd,rd); return 0;}int write_msg(s_info_t *arg,fd_set *rd,fd_set *wr){ char buf[BUF_ERR_SIZE]; assert(arg && rd && wr); FD_CLR(arg->fd,wr); arg->tm=time(0); for(n=0;arg->len>0;arg->len-=n){ n=write(arg->fd,arg->buf+n,arg->len); if(n==-1){ if(errno==EINTR) fprintf(stderr,"client %d error:%s\n",arg->fd,geterr_str(errno,buf,sizeof(buf))); } } if(n>0){ arg->callback=read_ FD_SET(arg->fd,rd); //设置接收水平位的大小,也是使select()下次唤醒的条件,linux下不支持这个选项。 //setsock_normalopt_int(arg->fd,SO_RCVLOWAT,arg->len); return 1; } fprintf(stderr,"client %d end\n",arg->fd); close(arg->fd); arg->fd=-1; //if(!FD_ISSET(fd,rd))FD_SET(fd,rd); return 0;}int read_listen_fd(int fd,s_info_t *arg,size_t len,fd_set *rd){ assert(arg && len); for(i=0;i<i++){ if(arg[i].fd==-1) } if(i==len){ fprintf(stderr,"The client too much\n");//如果没有客户端数量达到上限,则暂时将侦听描述符从读测试集合中移除 FD_CLR(fd,rd); } arg[i].fd=accept_client(fd); fprintf(stderr,"The new %d client\n",arg[i].fd); arg[i].callback=read_ arg[i].tm=time(0); FD_SET(arg[i].fd,rd); return arg[i].}int init_s_info(s_info_t *arg,size_t len){ assert(arg && len); bzero(arg,len*sizeof(s_info_t)); for(i=0;i<i++){ arg[i].fd=-1; }}int check_timeout(int lstfd,s_info_t *arg,size_t len,fd_set *rd,fd_set *wr){ time_ int i, assert(rd && wr && arg && len); tm=time(0); for(i=0;iTIMEOUTS)){ if(arg[i].callback==read_msg) FD_CLR(arg[i].fd,rd); if(arg[i].callback==write_msg) FD_CLR(arg[i].fd,wr); fprintf(stderr,"The client %d end\n",arg[i].fd); close(arg[i].fd); arg[i].fd=-1;//如果有失效的客户端,且侦听描述符不在读测试集合中,则加入读测试集合; if(!FD_ISSET(lstfd,rd))FD_SET(lstfd,rd); } if(arg[i].fd!=-1) fd=MAX(fd,arg[i].fd); }}int main(int argc,char **argv){ int i,n,clientfd,listenfd,maxfd, fd_set rd,wr,rdt, timeval_ s_info_t cltinfo[CLT_NUMS]; if(argc==2) listenfd=create_tcpsvr(0,atoi(argv[1])); else if(argc==3) listenfd=create_tcpsvr(argv[1],atoi(argv[2])); else{ fprintf(stderr,"usage %s [host ip] \n",argv[0]); exit(EXIT_FAILURE); } FD_ZERO(&rd); FD_ZERO(&wr); maxfd= FD_SET(listenfd,&rd); init_s_info(cltinfo,CLT_NUMS); while(1){ rdt= wrt= tm.tv_sec=TIMEOUTS; tm.tv_usec=0; n=select(maxfd+1,&rdt,&wrt,0,&tm); if(n==-1){ if(errno==EINTR) print_err("select()"); } //超时,检查超时的客户端描述符,并关闭; if(n==0){ maxfdt=check_timeout(listenfd,cltinfo,CLT_NUMS,&rd,&wr); maxfd=MAX(maxfdt,listenfd); } if(FD_ISSET(listenfd,&rdt)){ clientfd=read_listen_fd(listenfd,cltinfo,CLT_NUMS,&rd); maxfd=MAX(clientfd,maxfd); n--; } for(maxfdt=listenfd,i=0;n>0 && i<CLT_NUMS;i++){ if(cltinfo[i].fd!=-1 && (FD_ISSET(cltinfo[i].fd,&rdt) || FD_ISSET(cltinfo[i].fd,&wrt))){ n--;//如果有客户端结束或出错,且侦听描述符不在读测试集合中,则加入读测试集合; if(cltinfo[i].callback(&cltinfo[i],&rd,&wr)==0 && !FD_ISSET(listenfd,&rd)) FD_SET(listenfd,&rd); } if(cltinfo[i].fd!=-1) maxfdt=MAX(cltinfo[i].fd,maxfdt); } maxfd=MAX(maxfd,maxfdt); }} 2.[代码]创建并发连接的客户端 #include "unp.h"#define CONS 50#define STACKSIZE 4096*10typedef void *(*pthread_f)(void *);void *echo_str(void *arg){ char buf[BUFSIZ],* fd_set rdset, size_ int fd,maxfd,i,n, fd=(int) FD_ZERO(&rdset); FD_SET(fd,&rdset); maxfd= FD_SET(fileno(stdin),&rdset); maxfd=MAX(fileno(stdin),maxfd); for(flagin=0,i=1;;i++){ test= n=select(maxfd+1,&test,0,0,0); if(n==-1 && errno==EINTR) if(FD_ISSET(fileno(stdin),&test)){ if(fgets(buf,sizeof(buf),stdin)==0){ if(ferror(stdin)!=0){ print_err("fgets()"); } flagin=1; FD_CLR(fileno(stdin),&rdset); shutdown(fd,SHUT_WR); } len=strlen(buf); write_sock(fd,buf,len); } if(FD_ISSET(fd,&test)){ if((len=read(fd,buf,sizeof(buf)))==-1) print_err("echo_str(),read()"); if(len==0){ if(flagin==0) fprintf(stderr,"end %d connection,echo_str():server terminated.\n",fd); } fprintf(stdout,"%.*s",len,buf); } } return (void*)0;}pthread_t create_thread_conn(int fd,char *stack,size_t stacksize){ pthread_attr_ pthread_ assert(stack && stacksize); flag=pthread_attr_init(&attr); check_pthread_return(flag,"pthread_attr_init()"); flag=pthread_attr_setstack(&attr,stack,stacksize); check_pthread_return(flag,"pthread_attr_setstack()"); flag=pthread_create(&tid,&attr,(pthread_f)echo_str,(void*)fd); check_pthread_return(flag,"pthread_create()"); flag=pthread_attr_destroy(&attr); check_pthread_return(flag,"pthread_attr_destroy()");}int main(int argc,char **argv){ int fd,cons,i, pthread_t * char * if(argc!=4){ fprintf(stderr,"usage %s
\n",argv[0]); exit(EXIT_FAILURE); } cons=atoi(argv[3]); stack=(char*)malloc(STACKSIZE*(cons?cons:CONS)); tid=(pthread_t*)malloc(sizeof(pthread_t)*(cons?cons:CONS)); for(i=0;i<(cons?cons:CONS);i++){ fd=create_tcpclt(argv[1],atoi(argv[2])); fprintf(stderr,"new %d connection\n",fd); tid[i]=create_thread_conn(fd,stack+i*STACKSIZE,STACKSIZE); } for(i=0;i<(cons?cons:CONS);i++){ flag=pthread_join(tid[i],0); check_pthread_return(flag,"pthread_join()"); } free(stack); free(tid); exit(EXIT_SUCCESS);} 3.[文件] define.h~4KB 下载(18) #ifndef __DEFINE_H__#define__DEFINE_H__/*操作系统差异,包含文件差异*///#if !defined(_WIN32) && !defined(_WIN64)#define __UNIX__1//#endif#ifdef__UNIX__#include #include /*是否使用bzero(),bcopy(),bcmp()系列函数*/#define __BIT_OPER1#else#include #endif/*一般配置信息*///#define HAVE_ICONV_H/*C基本头文件*/#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _POSIX_THREADS#include #endif#ifndef EXIT_SUCCESS#define EXIT_SUCCESS0#endif#ifndef EXIT_FAILURE#define EXIT_FAILD -1#endif/*一个无效的地址引用*/extern char *__#define UNDEF ((void*)__quote)#if defined __cplusplus #if !defined __BEGIN_DECLS#define __BEGIN_DECLSextern "C" {#define __END_DECLS}#endif#else#define __BEGIN_DECLS#define __END_DECLS#endif#define __DEBUG_MODE1#define MAX(x,y)((x) > (y)?(x) : (y))#define MIN(x,y)((x) < (y)?(x) : (y))/*对齐字*/#ifndef ALIGN#define ALIGN(x)(((size_t)(x) + (sizeof(size_t) - 1)) & ~(sizeof(size_t) - 1))#endif/*对齐指定值*/#ifndef ALIGN_VAL#define ALIGN_VAL(a,size)((a) & ((size) - 1) ? (1 + ((a) | ((size) - 1))) : (a))#endif/*4kB缓冲*/#ifndef BUFSIZ#define BUFSIZ 4096#endif#undef BUF_SIZE#define BUF_SIZEBUFSIZ#define BUF_ERR_SIZE256/*真值定义*/#if !(defined TRUE) || !(defined FALSE)#define TRUETRUE#define FALSEFALSE#else#undefTRUE#undefFALSE#define TRUETRUE#define FALSEFALSE#endiftypedef enum BOOL{ERRCODE=-1,FALSE,TRUE} BOOL;/*数据重定义*/typedef typetypedetypedetypede/*扩展定义*/#ifndef FD_CLOEXEC#define FD_CLOEXEC0x01#endiftypedef struct statstat_t,*stat_p;typedef struct utimbufutimbuf_t,*utimbuf_p;typedef struct direntdirent_t,*dirent_p;typedef struct passwdpasswd_t,*passwd_p;typedef struct spwdspwd_t,*spwd_p;typedef struct groupgroup_t,*group_p;typedef struct utsnameutsname_t,*utsname_p;typedef time_t*time_p;typedef struct timevaltimeval_t,*timeval_p;typedef struct timespec timespec_t,*timespec_p;typedef struct tmtm_t,*tm_p;typedef struct tmstms_t,*tms_p;typedef int (*scandir_filter_f)(const dirent_t *dp);typedef int (*scandir_sort_f)(const dirent_t **dp1,const dirent_t **dp2);typedef jmp_bufjmp_buf_t;typedef struct sigactionsigaction_t;typedef union sigvalsigval_t;/*socket基本API*/typedef struct in_addr*in_add_p;typedef struct in6_addr*in6_addr_p;typedef struct sockaddr_insockaddr_in_t,*sockaddr_in_p;typedefstruct sockaddr_in6sockaddr_in6_t,*sockaddr_in6_p;typedefstruct sockaddrsockaddr_t,*sockaddr_p;typedef struct sockaddr_storage sockaddr_storage_t,*sockaddr_storage_p;typedef struct pollfdpollfd_t,*pollfd_p;typedef struct epoll_eventepoll_event_t,*epoll_event_p;/*信号处理函数*/typedef void (*sig_f)(int);typedef void (*sigrt_f)(int,siginfo_t *,void *);/*socket基本API*/#define LISTENQ20#define print_err(msg){char buf[BUF_ERR_SIZE];fprintf(stderr,"%s error:%s\n",(msg),geterr_str(errno,buf,sizeof(buf)));exit(EXIT_FAILURE);}#define check_pthread_return(flag,msg){ \int _flag= \if(_flag != 0){ \char buf[BUF_ERR_SIZE]; \fprintf(stderr,"%s error:%s\n",(msg),geterr_str(_flag,buf,sizeof(buf))); \exit(EXIT_FAILURE); \} \}#define DEF_PORT1500#endif 4.[文件] unp.h~587B 下载(17) #ifndef __UNP_H__#define__UNP_H__#include "define.h"__BEGIN_DECLSsig_fhandle_signal(int signo,sig_f func);char*geterr_str(int e,char *buf,size_t size);voidfill_sockaddr(sockaddr_in_p addr,socklen_t len,char *inet,int port);voidwrite_sock(int fd,char *buf,size_t len);intcreate_tcpsvr(char *inet,int port);intcreate_tcpclt(char *inet,int port);intaccept_client(int fd);voidrecycle_child_state(int signo);voidsetsock_normalopt_int(int fd,int opt,int val);voidgetsock_normalopt_int(int fd,int opt,int *val);__END_DECLS#endif 5.[文件] unp.c~3KB 下载(17) #include "unp.h"sig_f handle_signal(int signo,sig_f func){sigaction_t sigact,bzero(&sigact,sizeof(sigact));if(sigemptyset(&sigact.sa_mask)==-1)print_err("sigemptyset()");sigact.sa_handler=if(signo==SIGALRM){#ifdef SA_INTERRUPTsigact.sa_flags|=SA_INTERRUPT;#endif}else{#ifdef SA_RESTARTsigact.sa_flags|=SA_RESTART;#endif}if(sigaction(signo,&sigact,&old)==-1)print_err("sigaction()");return old.sa_}char *geterr_str(int e,char *buf,size_t size){assert(buf);bzero(buf,size);if(strerror_r(e,buf,size)==-1){fprintf(stderr,"strerror_r() error\n");exit(EXIT_FAILURE);}}void fill_sockaddr(sockaddr_in_p addr,socklen_t len,char *inet,int port){assert(addr);bzero(addr,len);addr->sin_family=AF_INET;addr->sin_port=htons(port?port:DEF_PORT);if(inet==0)addr->sin_addr.s_addr=htons(INADDR_ANY);else if(inet_pton(AF_INET,inet,&addr->sin_addr)==-1)print_err("fill_sockaddr(),inet_pton()");}void write_sock(int fd,char *buf,size_t len){size_t n,assert(buf);for(pos=0;len>0;len-=pos){if((n=write(fd,buf+pos,len))==-1){if(errno==EINTR){}print_err("write_sock(),write()");}pos+=n;}}int create_tcpsvr(char *inet,int port){sockaddr_in_assert(port);if((fd=socket(AF_INET,SOCK_STREAM,0))==-1)print_err("create_tcpsvr(),socket()");fill_sockaddr(&addr,sizeof(addr),inet,port);setsock_normalopt_int(fd,SO_REUSEADDR,1);if(bind(fd,(sockaddr_p)&addr,sizeof(addr))==-1)print_err("create_tcpsvr(),bind()");if(listen(fd,LISTENQ)==-1)print_err("create_tcpsvr(),listen()");}int create_tcpclt(char *inet,int port){sockaddr_in_assert(inet && port);if((fd=socket(AF_INET,SOCK_STREAM,0))==-1)print_err("create_tcpclt(),socket()");fill_sockaddr(&addr,sizeof(addr),inet,port);if(connect(fd,(sockaddr_p)&addr,sizeof(addr))==-1)print_err("create_tcpclt(),connect()");}intaccept_client(int fd){char buf[BUF_ERR_SIZE];__again:if((cltfd=accept(fd,0,0))==-1){if(errno==EINTR){fprintf(stderr,"accept() error:%s\n",geterr_str(errno,buf,sizeof(buf)));goto __}print_err("accept_client(),accept()");}}voidrecycle_child_state(int signo){if(signo==SIGCHLD){while(waitpid(-1,0,WNOHANG)>0);}}voidsetsock_normalopt_int(int fd,int opt,int val){if(setsockopt(fd,SOL_SOCKET,opt,&val,sizeof(int))==-1)print_err("setsock_normalopt_int()");}voidgetsock_normalopt_int(int fd,int opt,int *val){socklen_assert(val);len=sizeof(int);if(getsockopt(fd,SOL_SOCKET,opt,val,&len)==-1)print_err("getsock_normalopt_int()");}
上一集:没有了 下一集:
相关文章:&&&&&&&&&&&&&&&&
最新添加资讯
24小时热门资讯
附近好友搜索Nginx关键数据结构分析(一) ngx_buf_t - 推酷
Nginx关键数据结构分析(一) ngx_buf_t
在分析nginx的功能之前,首先看一下nginx使用的一些基础的数据结构及其用法,这样才能更好的理解以后的代码。
typedef struct ngx_buf_s
ngx_buf_t;
typedef void *
ngx_buf_tag_t;
struct ngx_buf_s {
/* start of buffer */
/* end of buffer */
ngx_buf_tag_t
/* 表示当前缓冲区的类型,如果是哪个模块使用就为该模块的ngx_module_t变量的地址 */
ngx_file_t
/* the buf's content could be changed */
/* 临时内存标志位,表示当前buf在内存中并且是可以修改的 */
temporary:1;
/* buf在内存中并且是不可以修改的*/
/* the buf's content is mmap()ed and must not be changed*/
/* buf的内存空间是由mmap生成的,不可以被修改*/
recycled:1;
in_file:1;
last_buf:1;
last_in_chain:1;
last_shadow:1;
temp_file:1;
/* STUB */
typedef struct ngx_chain_s ngx_chain_t;
struct ngx_chain_s {
ngx_buf_t *
ngx_chain_t
typedef struct {
} ngx_bufs_t;
其中要注意的是shadow指针,该指针用于指向原有的内存空间从而减少了nginx的内存消耗,该技术使用起来很高端,在能力低端的时候不要使用
在结构体中了start、end表示的是该块指定的内存的开始和结束,而position和last则是提醒程序本次使用的内存空间只有这些。
而ngx_bufs_t则应该是起到一个管理的作用,用于说明当前使用的bufs的数量和每个buf的存储空间的大小
// ngx_core.h
#define NGX_CHAIN_ERROR
(ngx_chain_t *) NGX_ERROR
#define ngx_buf_in_memory(b)
(b-&temporary || b-&memory || b-&mmap)
#define ngx_buf_in_memory_only(b)
(ngx_buf_in_memory(b) && !b-&in_file)
#define ngx_buf_special(b)
((b-&flush || b-&last_buf || b-&sync)
&& !ngx_buf_in_memory(b) && !b-&in_file)
#define ngx_buf_sync_only(b)
&& !ngx_buf_in_memory(b) && !b-&in_file && !b-&flush && !b-&last_buf)
#define ngx_buf_size(b)
(ngx_buf_in_memory(b) ? (off_t) (b-&last - b-&pos):
(b-&file_last - b-&file_pos))
#define ngx_alloc_buf(pool)
ngx_palloc(pool, sizeof(ngx_buf_t))
#define ngx_calloc_buf(pool) ngx_pcalloc(pool, sizeof(ngx_buf_t))
#define ngx_free_chain(pool, cl)
cl-&next = pool-&
pool-&chain = cl
ngx_buf_t *ngx_create_temp_buf(ngx_pool_t *pool, size_t size);
ngx_chain_t *ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs);
ngx_chain_t *ngx_alloc_chain_link(ngx_pool_t *pool);
ngx_buf_t *
ngx_create_temp_buf(ngx_pool_t *pool, size_t size)
ngx_buf_t *b;
b = ngx_calloc_buf(pool);
if (b == NULL) {
return NULL;
b-&start = ngx_palloc(pool, size);
if (b-&start == NULL) {
return NULL;
b-&pos = b-&
b-&last = b-&
b-&end = b-&last +
b-&temporary = 1;
这段代码是表示怎样创建生成一个temp的buf,并且从代码中也可以看到一段buf的内存空间是怎样分配的,通过ngx_palloc这个函数来完成分配的,并且由于在初始创建buf结构体的时候使用的函数是ngx_calloc_buf,所以针对分配的内存实行了清零操作
ngx_chain_t *
ngx_alloc_chain_link(ngx_pool_t *pool)
ngx_chain_t
cl = pool-&
pool-&chain = cl-&
cl = ngx_palloc(pool, sizeof(ngx_chain_t));
if (cl == NULL) {
return NULL;
而这段代码则是表明在nginx中,chain是通过pool来生成的,而且每次通过在pool的开头提取的方式来完成的
ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs)
ngx_buf_t *b;
ngx_chain_t
*chain, *cl, **
p = ngx_palloc(pool, bufs-&num * bufs-&size);
if (p == NULL) {
return NULL;
for (i = 0; i & bufs-& i++) {
b = ngx_calloc_buf(pool);
if (b == NULL) {
return NULL;
b-&temporary = 1;
b-&start =
p += bufs-&
cl = ngx_alloc_chain_link(pool);
if (cl == NULL) {
return NULL;
ll = &cl-&
*ll = NULL;//到最后将生成的ngx_chain_t的next指针指向NULL,表明整个链表生成完毕。
这段代码则表明了ngx_bufs_t类型是怎样运用的,利用num 和 size来创建一段缓冲区,该缓冲区用于表示ngx_chain_t中的所有的节点中的buf都是从该段缓冲区中分配出来的,但是所有的cl都是从pool中的chain中分配下来重新利用的或者是重新创建的(详细情况查看ngx_alloc_chain_link函数。
从这里我们可以看到nginx的内存分配管理其实本质上或者说基础的方法和手段是利用ngx_pool_t结构体。所以说下一步需要对这个nginx中重要的内存分配管理的部分进行查看和分析。
然后还存在多个针对ngx_buf_t类型的基本操作(其实应该说是针对ngx_chain_t类型的基本操作
ngx_chain_add_copy
ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in)
ngx_chain_t
/* 遍历chain,查找到chain的最后结尾 */
for (cl = * cl = cl-&next) {
ll = &cl-&
/* 遍历in,并且创建分配chain的基本节点,并将其buf指向in的部分 */
while (in) {
cl = ngx_alloc_chain_link(pool);
if (cl == NULL) {
return NGX_ERROR;
cl-&buf = in-&
ll = &cl-&
*ll = NULL;//最后将最后一个chain节点的next指向一个NULL指针
return NGX_OK;
该函数是在现有的chain的基础上将一个链表“复制”连接到该chain后面,但是从操作中我们可以看到,这个过程虽然说是“复制”,但是针对buf中实际的内存的操作仅仅是将针对连接上罢了。
ngx_chain_t *
ngx_chain_get_free_buf(ngx_pool_t *p, ngx_chain_t **free)
ngx_chain_t
if (*free) {
*free = cl-&
cl-&next = NULL;
cl = ngx_alloc_chain_link(p);
if (cl == NULL) {
return NULL;
cl-&buf = ngx_calloc_buf(p);
if (cl-&buf == NULL) {
return NULL;
cl-&next = NULL;
这段代码从名字上来看是获得一个free的buf,实际上是从一个free的链表中获得一个chain节点或者是重新分配一个chain节点nginx中的链表操作很多都是头链表操作,即如果需要添加链表元素的话通常都将该元素添加到头上
ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free, ngx_chain_t **busy,
ngx_chain_t **out, ngx_buf_tag_t tag)
ngx_chain_t
if (*busy == NULL) {
for (cl = * cl-& cl = cl-&next) { /* void */ }
cl-&next = *
*out = NULL;
while (*busy) {
if (ngx_buf_size(cl-&buf) != 0) {
if (cl-&buf-&tag != tag) {
*busy = cl-&
ngx_free_chain(p, cl);
cl-&buf-&pos = cl-&buf-&
cl-&buf-&last = cl-&buf-&
*busy = cl-&
cl-&next = *
需要处理的链表是out指针指向的链表,而free指向的应该就是当前存在的free链表,而busy链表则是当前存在的busy链表,该链表也是待处理的链表
所以开始的时候需要判断将out应该放到哪一个位置,如果busy当前就存在的话,那么就应该将out放置到busy的最后,如果当前busy链表不存在,那么处理就是
将其作为busy链表进行处理
而后面的操作则是说明从头对busy链表实行检查,如果busy链表中的buf还存在需要处理的内存空间,那么就需要停止处理,否则就将其置为空(即对last和pos进行处理)
ngx_chain_t *
ngx_chain_update_sent(ngx_chain_t *in, off_t sent)
for ( /* void */ ; in = in-&next) {
if (ngx_buf_special(in-&buf)) {
if (sent == 0) {
size = ngx_buf_size(in-&buf);
if (sent &= size) {
if (ngx_buf_in_memory(in-&buf)) {
in-&buf-&pos = in-&buf-&
if (in-&buf-&in_file) {
in-&buf-&file_pos = in-&buf-&file_
if (ngx_buf_in_memory(in-&buf)) {
in-&buf-&pos += (size_t)
if (in-&buf-&in_file) {
in-&buf-&file_pos +=
该函数处理的情况就更加的容易理解了,就是说当发送了sent字节之后需要对当前使用的缓冲区做处理,并返回当前仍未处理过的缓冲区指针。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
人生一年又一年,只要每年都有所积累,有所成长,都有那么一次自己认为满意的花开时刻就好。即使一时不顺,也要敞开胸怀。生命的荣枯并不是简单的重复,一时的得失不是成败的尺度。花开不是荣耀,而是一个美丽的结束,花谢也不是耻辱,而是一个低调的开始。
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
先看中后部的一段代码:typedef uint16_t packetbuf_attr_t;struct packetbuf_attr { packetbuf_attr_};struct packetbuf_addr { linkaddr_};结构体packetbuf_attr表示包的属性,attr为attribute的缩写。结构体packetbuf_addr表示包地址,linkaddr_t上一篇日志讲过,一个16位或64位的数据之后列出属性的分类:#define PACKETBUF_ATTR_PACKET_TYPE_DATA & & & & & & 0#define PACKETBUF_ATTR_PACKET_TYPE_ACK & & & & & & & 1#define PACKETBUF_ATTR_PACKET_TYPE_STREAM & & & & &2#define PACKETBUF_ATTR_PACKET_TYPE_STREAM_END & 3#define PACKETBUF_ATTR_PACKET_TYPE_TIMESTAMP & & 4然后是属性值,放在一个枚举里面:enum {& PACKETBUF_ATTR_NONE,& /* Scope 0 attributes: used only on the local node. */& PACKETBUF_ATTR_CHANNEL,& PACKETBUF_ATTR_NETWORK_ID,& PACKETBUF_ATTR_LINK_QUALITY,& PACKETBUF_ATTR_RSSI,& PACKETBUF_ATTR_TIMESTAMP,& PACKETBUF_ATTR_RADIO_TXPOWER,& PACKETBUF_ATTR_LISTEN_TIME,& PACKETBUF_ATTR_TRANSMIT_TIME,& PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS,& PACKETBUF_ATTR_MAC_SEQNO,& PACKETBUF_ATTR_MAC_ACK,& PACKETBUF_ATTR_IS_CREATED_AND_SECURED,&&/* Scope 1 attributes: used between two neighbors only. */#if PACKETBUF_WITH_PACKET_TYPE& PACKETBUF_ATTR_PACKET_TYPE,#endif#if NETSTACK_CONF_WITH_RIME& PACKETBUF_ATTR_PACKET_ID,& PACKETBUF_ATTR_RELIABLE,& PACKETBUF_ATTR_REXMIT,& PACKETBUF_ATTR_MAX_REXMIT,& PACKETBUF_ATTR_NUM_REXMIT,#endif /* NETSTACK_CONF_WITH_RIME */& PACKETBUF_ATTR_PENDING,& PACKETBUF_ATTR_FRAME_TYPE,#if LLSEC802154_SECURITY_LEVEL& PACKETBUF_ATTR_SECURITY_LEVEL,& PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1,& PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3,#if LLSEC802154_USES_EXPLICIT_KEYS& PACKETBUF_ATTR_KEY_ID_MODE,& PACKETBUF_ATTR_KEY_INDEX,& PACKETBUF_ATTR_KEY_SOURCE_BYTES_0_1,#endif /* LLSEC802154_USES_EXPLICIT_KEYS */#endif /* LLSEC802154_SECURITY_LEVEL *//* Scope 2 attributes: used between end-to-end nodes. */#if NETSTACK_CONF_WITH_RIME& PACKETBUF_ATTR_HOPS,& PACKETBUF_ATTR_TTL,& PACKETBUF_ATTR_EPACKET_ID,& PACKETBUF_ATTR_EPACKET_TYPE,& PACKETBUF_ATTR_ERELIABLE,#endif /* NETSTACK_CONF_WITH_RIME */&/* These must be last */& PACKETBUF_ADDR_SENDER,& PACKETBUF_ADDR_RECEIVER,#if NETSTACK_CONF_WITH_RIME& PACKETBUF_ADDR_ESENDER,& PACKETBUF_ADDR_ERECEIVER,#endif /* NETSTACK_CONF_WITH_RIME */& PACKETBUF_ATTR_MAX};这里需要注意的是,enum里的第一个值如果不赋值则为0,其它值依次加1。枚举里的最后一个元素是PACKETBUF_ATTR_MAX,它应该仅仅用来标识最后一个枚举值。或用这个值来引用枚举里的最大值。下来打开Packetbuff.c文件来学习:struct packetbuf_attr packetbuf_attrs[PACKETBUF_NUM_ATTRS];struct packetbuf_addr packetbuf_addrs[PACKETBUF_NUM_ADDRS];之前讲的两个结构体,主要用在这了,放在数组里面。先看看PACKETBUF_NUM_ADDRS的定义:#if NETSTACK_CONF_WITH_RIME #define PACKETBUF_NUM_ADDRS 4#else /* NETSTACK_CONF_WITH_RIME */ #define PACKETBUF_NUM_ADDRS 2也就是说这个packetbuf_addrs存放2个或4个地址再看看PACKETBUF_NUM_ATTRS的定义:#define PACKETBUF_NUM_ATTRS & (PACKETBUF_ATTR_MAX - PACKETBUF_NUM_ADDRS)现在可以确定packetbuf_attr的可能值为枚举里列出的属性,我大略数了一下,PACKETBUF_ATTR_MAX满打满算最大的值为36。为何要用属性的个数减去地址的个数?两者数量上没有联系吧,搞不懂,往下看再说吧。下面是关于包缓冲属性的一些函数:packetbuf_attr_clearvoid&packetbuf_attr_clear(void){
for(i = 0; i & PACKETBUF_NUM_ATTRS; ++i) {
packetbuf_attrs[i].val = 0; } for(i = 0; i & PACKETBUF_NUM_ADDRS; ++i) {
linkaddr_copy(&packetbuf_addrs[i].addr, &linkaddr_null); }}就是把两个数组清0,没啥好说的。packetbuf_attr_copytovoid&packetbuf_attr_copyto(struct packetbuf_attr *attrs,
& &struct packetbuf_addr *addrs){ memcpy(attrs, packetbuf_attrs, sizeof(packetbuf_attrs)); memcpy(addrs, packetbuf_addrs, sizeof(packetbuf_addrs));}把这两个数组拷贝别给人packetbuf_attr_copyfromvoid&packetbuf_attr_copyfrom(struct packetbuf_attr *attrs,
& & &struct packetbuf_addr *addrs){& memcpy(packetbuf_attrs, attrs, sizeof(packetbuf_attrs));& memcpy(packetbuf_addrs, addrs, sizeof(packetbuf_addrs));}从attrs和addrs里拷贝数据到两个数组packetbuf_set_attrint&packetbuf_set_attr(uint8_t type, const packetbuf_attr_t val){ packetbuf_attrs[type].val = return 1;}设置属性,enum里的值从0开始计,数组索引也是从0开始计,那么枚举元素所代表的值正好对应它在数组中的位置。例如PACKETBUF_ATTR_NONE=0,而正好可以通过packetbuf_attrs[0]访问它所存放的val,至于这个val是什么,就不得而知了。反正得出结论,type变量直接用枚举元素即可。packetbuf_attrpacketbuf_attr_t &packetbuf_attr(uint8_t type){ return packetbuf_attrs[type].}感觉象C#里面的属性访问器,上面的函数是set访问器,这个函数就是get访问器。packetbuf_set_addrpacketbuf_set_addr(uint8_t type, const linkaddr_t *addr){ linkaddr_copy(&packetbuf_addrs[type - PACKETBUF_ADDR_FIRST].addr, addr); return 1;}先来看看PACKETBUF_ADDR_FIRST的定义:#define &PACKETBUF_ADDR_FIRST &PACKETBUF_ADDR_SENDER这个挺有意思,我们从上面拷贝enum里的最后几句来看看:/* These must be last */& PACKETBUF_ADDR_SENDER,& PACKETBUF_ADDR_RECEIVER,#if NETSTACK_CONF_WITH_RIME& PACKETBUF_ADDR_ESENDER,& PACKETBUF_ADDR_ERECEIVER,#endif /* NETSTACK_CONF_WITH_RIME */& PACKETBUF_ATTR_MAX这里假设没有定义NETSTACK_CONF_WITH_RIME宏,则以上语句变为:& PACKETBUF_ADDR_SENDER,& PACKETBUF_ADDR_RECEIVER,& PACKETBUF_ATTR_MAX那么现在就可以确定,addrs数组里的两个元素正好对应 PACKETBUF_ADDR_SENDER PACKETBUF_ADDR_RECEIVER。而如果定义了NETSTACK_CONF_WITH_RIME宏,则addrs数组有四个元素,分别对应 PACKETBUF_ADDR_SENDER PACKETBUF_ADDR_RECEIVER PACKETBUF_ADDR_ESENDER, PACKETBUF_ADDR_ERECEIVER,则type减以上的第一个元素的枚举值就可以计算出它在addr数组中的值。最后的结论是type必须是以上四个枚举值之一。packetbuf_addrpacketbuf_addr(uint8_t type){ return &packetbuf_addrs[type - PACKETBUF_ADDR_FIRST].}上面那个函数是set访问器,那这个就是get访问器。packetbuf_holds_broadcastpacketbuf_holds_broadcast(void){& return linkaddr_cmp(&packetbuf_addrs[PACKETBUF_ADDR_RECEIVER - PACKETBUF_ADDR_FIRST].addr, &linkaddr_null);}这个函数实际上就是把PACKETBUF_ADDR_RECEIVER所对应的地址清0。根据函数名称推断,应该是发送广播消息,所以rime中的广播地址为全0,这点跟TCP/IP协议是不同的。个人猜测。这篇还算顺利,不过对packetbuf没有什么提示,下篇可能要难产了,继续研究。
阅读(667)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
在LOFTER的更多文章
loftPermalink:'',
id:'fks_',
blogTitle:'Contiki学习笔记---rime(2)------packetbuf_attr',
blogAbstract:'地址讲完了,下面讲什么,有点头痛。网络上传来传去的其实都是数据包,那就讲包吧。Contiki下有一个Packetbuff,翻译出来叫包缓冲,应该是个数据包的基础类,就从它开始吧。在\\core\\net目录下,Packetbuf.h头文件,关于包头和包数据这一段昨天搞了一个晚上到今天为了一个变量至今都没搞明白,真是折磨人,无人可问是很痛苦的。先讲包缓冲的另一部分吧,弄完这部分或许会有意外收获。先看中后部分的一段代码:',
blogTag:'contikit,rime',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:7,
publishTime:5,
permalink:'blog/static/',
commentCount:7,
mainCommentCount:4,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'人生一年又一年,只要每年都有所积累,有所成长,都有那么一次自己认为满意的花开时刻就好。即使一时不顺,也要敞开胸怀。生命的荣枯并不是简单的重复,一时的得失不是成败的尺度。花开不是荣耀,而是一个美丽的结束,花谢也不是耻辱,而是一个低调的开始。\r\n',
hmcon:'1',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}

我要回帖

更多关于 define 的文章

 

随机推荐