当前位置: 首页 > 工具软件 > libESMTP > 使用案例 >

邮件Socket IO实现 - 参考libESMTP

许子平
2023-12-01
关于libESMTP
            libESMTP, version 1.0
                  -- oOo --
            Brian Stafford  <brian@stafford.uklinux.net>

之前我自己也写过一个简单的Socket IO操作封装,主要目标是实现一个循环列表,把socket fd封装起来,通过这个循环列表建立它的输入缓冲。数据结构的定义为:
#define KAPOK_FILE_BUF_LEN  1024

typedef struct
{
    int kapok_file_magic;
    int el_flag;
    int fd;
    int read_head, read_tail;
    int fd_status;
    unsigned char read_buf[KAPOK_FILE_BUF_LEN];

} KapokFile;

enum
{
    KF_STATUS_OK,
    KF_STATUS_EOF,      //一般来说不应该有这个状态,因为socket没有eof的概念
    KF_STATUS_INVALID
};

而libESMTP提供的sio数据结构(及算法)就复杂很多了。查看siobuf.h可以看到它的所有外露接口:

#define SIO_BUFSIZE 2048 /* arbitrary, not too short, not too long */
#define SIO_READ    1
#define SIO_WRITE   2

typedef void (*recodecb_t) (char **dstbuf, int *dstlen,
                const char *srcbuf, int srclen, void *arg);
typedef void (*monitorcb_t) (const char *buffer, int length, int direction,
                 void *arg);

struct siobuf *sio_attach(int sdr, int sdw, int buffer_size);
void sio_detach(struct siobuf *sio);
void sio_set_monitorcb(struct siobuf *sio, monitorcb_t cb, void *arg);
void sio_set_timeout(struct siobuf *sio, int milliseconds);
void sio_set_securitycb(struct siobuf *sio, recodecb_t encode_cb,
                recodecb_t decode_cb, void *arg);
int sio_poll(struct siobuf *sio,int want_read, int want_write, int fast);
void sio_write(struct siobuf *sio, const void *bufp, int buflen);
void sio_flush(struct siobuf *sio);
void sio_mark(struct siobuf *sio);
int sio_fill(struct siobuf *sio);
int sio_read(struct siobuf *sio, void *bufp, int buflen);
char *sio_gets(struct siobuf *sio, char buf[], int buflen);
int sio_printf(struct siobuf *sio, const char *format, ...)
           __attribute__ ((format (printf, 2, 3))) ;
void *sio_set_userdata (struct siobuf *sio, void *user_data);
void *sio_get_userdata (struct siobuf *io);


#ifdef USE_TLS
int sio_set_tlsclient_ssl (struct siobuf *sio, SSL *ssl);
int sio_set_tlsserver_ssl (struct siobuf *sio, SSL *ssl);
#endif

1. attach/detach
用来关联和去关联socket套接字到SIO数据结构,这个过程中,套接字并没有被关闭。我设计的数据结构就只提供KapokFile的创建(关联)和关闭,在关闭时,套接字也会被关闭。从某个角度来说,我的设计参考了FILE数据结构的实现。

2. timeout设置
我的实现在timeout是在每次get/put中通过显式参数输入的。这里把timeout做到数据结构中。sio的timeout使用poll实现,而我原来的设计采用了select为实现,道理是一样的。

3. monitor call back
一个有利于调试的选项

4. security/recode call back
一个编码转译扩展接口,可以把邮件内容进行加密传送。

5. poll
对SIO数据结构的poll接口封装。查看源代码可以看到它支持SSL,而且利用SIO提供的读缓冲区,可以快速返回数据,提高处理效率。

6. write/flush/mark
写相关的函数,flush是真正的写,mark可以用来设置一个flush_mark的位置标置。如果flush_mark存在,则flush的目标不是整个有效缓冲区,而是flush以flush_mark指定的邮件。
write就是典型的套接字缓冲读写实现。配套实现有raw_write()函数

7. read/fill
fill和flush有点相似

8. gets/printf
高级点的读写操作

整体而言,SIO和我设计的KapokFile的区别有下面几点:

1.加入了monitor call back,支持联机monitor
2.加入recode call back,支持SSL等加密方式
3. 采用memmove则不是环循一维表的方式来处理内存
4. 提供flush_mark,而不是全面flush(觉得实用性不大)
5. 采用attach/detach来管理套接字关联,更加灵活。不过我的实现也可以接受。
6. 我没有把write_buf加入到数据结构中去。

还有一点就是sio采用双描述字,分别表示读和写。



 类似资料: