shttpd源码分析(3)几个重要数据结构

shttpd中为了简化处理将服务器与客户端之间的交互抽象成流(stream),流中包含建立的连接的信息、IO类型、IO操作方法(封装在io_class中)、最后读的字节的位置、头部长度、内容长度、流的当前状态标志等。

 

struct stream
1 /*
2 * Data exchange stream. It is backed by some communication channel:
3 * opened file, socket, etc. The 'read' and 'write' methods are
4 * determined by a communication channel.
5 */
6  struct stream {
7 struct conn *conn;
8 union channel chan; /* Descriptor */
9 struct io io; /* IO buffer */
10 const struct io_class *io_class; /* IO class */
11 int nread_last; /* Bytes last read */
12 int headers_len;
13 big_int_t content_len;
14 unsigned int flags;
15  #define FLAG_HEADERS_PARSED 1
16  #define FLAG_SSL_ACCEPTED 2
17  #define FLAG_R 4 /* Can read in general */
18  #define FLAG_W 8 /* Can write in general */
19  #define FLAG_CLOSED 16
20  #define FLAG_DONT_CLOSE 32
21  #define FLAG_ALWAYS_READY 64 /* File, dir, user_func */
22 };
23  

 

再来看看流结构中的几个结构struct conn、union channel、struct io、const struct io_class

 

先看看conn 结构的定义,其中保存了conn 结构(struct llhead)的链表、shttpd上下文(struct shttpd_ctx)、封装了远程socket的结构(struct usa)、创建时间(time_t)、过期时间(time_t)、本地端口、回复状态、请求方法、解码后的uri、HTTP主版本号、HTTP此版本号、请求行、请求头部、uri中的QUERY_STRING部分、PATH_INFO、Mime类型、解析过后的头部结构(struct headers)、本地流和远程流。

 

代码
struct conn {
struct llhead link; /* Connections chain */
struct shttpd_ctx *ctx; /* Context this conn belongs to */
struct usa sa; /* Remote socket address */
time_t birth_time;
/* Creation time */
time_t expire_time;
/* Expiration time */

int loc_port; /* Local port */
int status; /* Reply status code */
int method; /* Request method */
char *uri; /* Decoded URI */
unsigned
long major_version; /* Major HTTP version number */
unsigned
long minor_version; /* Minor HTTP version number */
char *request; /* Request line */
char *headers; /* Request headers */
char *query; /* QUERY_STRING part of the URI */
char *path_info; /* PATH_INFO thing */
const char *mime_type; /* Mime type */

struct headers ch; /* Parsed client headers */

struct stream loc; /* Local stream */
struct stream rem; /* Remote stream */

#if !defined(NO_SSI)
void *ssi; /* SSI descriptor */
#endif /* NO_SSI */
};

 

 

接下来看看union channel,保存交流的类型的信息。比如,如果是文件,则使用channel.fd;如果是socket,则使用channel.sock

 

代码
/*
* The communication channel
*/
union channel {
int fd; /* Regular static file */
int sock; /* Connected socket */
struct {
int sock; /* XXX important. must be first */
SSL
*ssl; /* shttpd_poll() assumes that */
} ssl;
/* SSL-ed socket */
struct {
DIR
*dirp;
char *path;
} dir;
/* Opened directory */
struct {
void *state; /* For keeping state */
union variant func;
/* User callback function */
void *data; /* User defined parameters */
} emb;
/* Embedded, user callback */
};

接着看看io结构,这个主要是保存io操作的一些状态信息

 

/*
* I/O buffer descriptor
*/
struct io {
char *buf; /* IO Buffer */
size_t size;
/* IO buffer size */
size_t head;
/* Bytes read */
size_t tail;
/* Bytes written */
size_t total;
/* Total bytes read */
};

 

再来看看io_class的结构,包括IO类别的名称、此类IO的读写和关闭操作的函数指针。

这里使用函数指针的好处是提供统一的接口调用,而可以在实际调用的时候使用不同的实现。这就类似于c++中的多态吧,只是这里用c的方式来实现。

 

/*
* IO class descriptor (file, directory, socket, SSL, CGI, etc)
* These classes are defined in io_*.c files.
*/
struct io_class {
const char *name;
int (*read)(struct stream *, void *buf, size_t len);
int (*write)(struct stream *, const void *buf, size_t len);
void (*close)(struct stream *);
};

 

例如在io_socket.c中定义的io_scoket

 

const struct io_class io_socket = {
"socket",
read_socket,
write_socket,
close_socket
};

然后在io_socket.c中是实现了read_socket、write_socket、close_socket来完成读写和关闭socket的操作

posted on 2010-09-14 22:23  雨中漫漫行  阅读(1845)  评论(0)    收藏  举报