本文主要是介绍【Hexler】Ubuntu下的简单Smtp Pop3邮件收发服务器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
前段时间做了一个邮件服务器,其实操作都不难,这个里面的难点其实就是这个项目得需要用到一些技术,代码量会比较多,容易出错一点,只要在写代码的时候每实现一个功能就仔细测试一下,这样就会简单很多。
由于我只写了服务器端,注释也写的比较多,所以就不贴演示图了,客户端用的是微软比较老的客户端outlook。
直接贴代码了,如果有人有需要可以参考一下,有问题或者指点也可以评论问我哦。
common.h
#ifndef COMMON_H
#define COMMON_H
#define MAX_MAIL (1024)
#define MAX_ATTACHMENT (7 * 1024)
#define USERFILE "table.txt"
typedef struct mail
{char send[80]; //发送者地址char recv[80]; //接收者地址char subject[80]; //主题字char filename[80]; //文件名char raw[MAX_MAIL]; //邮件内容char atta[MAX_ATTACHMENT]; //附件内容int len; //附件长度
} mail_t;
typedef struct subject_ctrl
{char command[16]; //命令字 8LED 7SHU MOTO CHANGETABLEint bulb; //灯的号数(1~8)int signal; //七段数码管显示信号(0~99)int revo; //电机转数(0,1000)int bulb_ctrl; //控制信号(0关灯,1开灯)int result; //0表示控制成功,-1表示控制失败
} ctrl_t;
typedef struct table
{char username[10]; // 邮件用户名char password[10]; //用户密码
}table_t;
#endif
central.c
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "net.h"
#include "mailrecv.h"typedef struct Accept
{struct sockaddr_in cid_addr;int cid;} Accept_t;
int Socket(int domain, int type, int protocol);
void Bind(int sockfd, const char *ip, short Port);
void Listen(int sockfd, int backlog);
void Print_cid(const struct sockaddr_in *addr);
void *pop3(void *arg);
void *smtp(void *arg);
char info[2048] = "";
mail_t *mail;
table_t table = {0};
struct subject_ctrl ctrl = {0};
void mail_guard();
/************************************************* 函数名:int main()* 功能:实现smtp与pop3服务* 参数:* * 返回值:* 成功:0* 失败:-1* *********************************************/
int main()
{pid_t pid = fork();if (pid < 0){printf("进程创建失败\n");return -1;}if (pid == 0) //子进程1{printf("子进程1\n");int sid = Socket(AF_INET, SOCK_STREAM, 0);int cid = -1;Bind(sid, "192.168.206.129", 10086);Listen(sid, 5);struct sockaddr_in cid_addr;socklen_t len = sizeof(cid_addr);pthread_t newthread;pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);Accept_t Accept;while (1){cid = accept(sid, (struct sockaddr *)&cid_addr, &len);Accept.cid_addr = cid_addr;Accept.cid = cid;if (cid < 0){perror("accept:");exit(-1);}//Print_cid(&cid_addr);pthread_create(&newthread, &attr, smtp, &Accept);}}pid_t pid2 = fork();if (pid2 < 0){printf("进程创建失败\n");return -1;}if (pid2 == 0) //子进程2{printf("子进程2\n");int sid1 = Socket(AF_INET, SOCK_STREAM, 0);int cid1 = -1;Bind(sid1, "192.168.206.129", 10010);Listen(sid1, 5);struct sockaddr_in cid_addr1;socklen_t len = sizeof(cid_addr1);pthread_t newthread1;pthread_attr_t attr1;pthread_attr_init(&attr1);pthread_attr_setdetachstate(&attr1, PTHREAD_CREATE_DETACHED);Accept_t Accept1;while (1){cid1 = accept(sid1, (struct sockaddr *)&cid_addr1, &len);Accept1.cid_addr = cid_addr1;Accept1.cid = cid1;if (cid1 < 0){perror("accept:");exit(-1);}//Print_cid(&cid_addr1);pthread_create(&newthread1, &attr1, pop3, &Accept1);}}int icuc = 0;int fx = open("/usr/mail/icu", O_RDWR | O_CREAT, 0666);if (fx <= 0){perror("初始化icu文件打开失败:");return -1;}write(fx, &icuc, sizeof(icuc));if (pid != 0){printf("杀死父进程\n");exit(0);}if (setsid() < 0){printf("创建会话失败\n");}chdir("/usr/mail");umask(0);for (size_t i = 0; i < getdtablesize(); i++){close(i);}close(fx);return 0;
}
/************************************************* 函数名:void *smtp(void *arg)* 功能:实现smtp服务* 参数:* arg:传递已经建立好连接的套接字* 返回值:* 无* *********************************************/
void *smtp(void *arg)
{Accept_t *Accept = (Accept_t *)arg;struct sockaddr_in cid_addr = Accept->cid_addr;int cid = Accept->cid;int fd;char filename[100] = "";mail_t *mail;int fx;int icu;fx = open("/usr/mail/icu", O_RDWR | O_CREAT, 0666);if (fx <= 0){perror("icu文件打开失败:");exit(-1);}read(fx, &icu, sizeof(icu));lseek(fx, 0, SEEK_SET);mail = malloc(sizeof(mail_t));handleconnection(cid, mail, &table);parsemail(mail, &ctrl, info, &table);icu++;write(fx, &icu, sizeof(icu));sprintf(filename, "//usr//mail//%s//%d%s", "letter", icu, table.username);fd = open(filename, O_RDWR | O_CREAT, 0666);if (fd <= 0){perror("邮件文件打开失败:");exit(-1);}write(fd, info, strlen(info));free(mail);mail = NULL;close(fd);close(fx);close(cid);
}
/************************************************* 函数名:void *pop3(void *arg)* 功能:实现pop3服务* 参数:* arg:传递已经建立好连接的套接字* 返回值:* 无* *********************************************/
void *pop3(void *arg)
{int icu;char yy;Accept_t *Accept = (Accept_t *)arg;struct sockaddr_in cid_addr = Accept->cid_addr;int cid = Accept->cid;table_t table={0};int fx;char icuc = '0';fx = open("/usr/mail/icu", O_RDWR | O_CREAT, 0666);if (fx <= 0){perror("icu文件打开失败:");exit(-1);}read(fx, &icu, sizeof(icu));pop3Connection(cid, info, &table, icu);if (icu > 0)icu--;lseek(fx, 0, SEEK_SET);write(fx, &icu, sizeof(icu));close(cid);mail = NULL;close(fx);mail = NULL;
}
mailrecv.h
#include "base64.h"int getusername(int sockfd, struct table *p); //SMTP
int getpassword(int sockfd, struct table *p);
int getfromaddress(int sockfd, struct mail *pmail);
int gettoaddress(int sockfd, struct mail *pmail);
int getbody(int sockfd, struct mail *pmail);#endif
mailrecv.c
#include "mailrecv.h"/************************************************* 函数名:int getusername(int sockfd, struct table *p)* 功能:获取用户名 并解码* 参数:* sockfd:套接字* p:存放解析之后的用户名的结构体* 返回值:* 成功:0* 失败:-1* *********************************************/
int getusername(int sockfd, struct table *p)
{if (sockfd < 2){return -1;}char buf[128] = "";read(sockfd, buf, sizeof(buf) - 1);buf[strlen(buf) - 2] = '\0';strcpy(buf, base64_decode(buf));strcpy(p->username, buf);return 0;
}
/************************************************* 函数名:int getpassword(int sockfd, struct table *p)* 功能:获取密码 并解码* 参数:* sockfd:套接字* p:存放解析之后的密码的结构体* 返回值:* 成功:0* 失败:-1* *********************************************/
int getpassword(int sockfd, struct table *p)
{if (sockfd < 2){return -1;}char buf[128] = "";read(sockfd, buf, sizeof(buf) - 1);buf[strlen(buf) - 2] = '\0';strcpy(buf, base64_decode(buf));strcpy(p->password, buf);return 0;
}
/************************************************* 函数名:int getfromaddress(int sockfd, struct mail *pmail)* 功能:获取邮件信息中的发送方的地址* 参数:* sockfd:套接字* pmail:用来存放发送方地址的结构体* 返回值:* 成功:0* 失败:-1* *********************************************/
int getfromaddress(int sockfd, struct mail *pmail)
{if (sockfd < 2){return -1;}char buf[128] = "";read(sockfd, buf, sizeof(buf) - 1);strcpy(pmail->send, buf);printf("地址:%s\n", buf);return 0;
}
/************************************************* 函数名:int gettoaddress(int sockfd, struct mail *pmail)* 功能:获取邮件信息中的目的地址* 参数:* sockfd:套接字* pmail:用来存放目的地址的结构体* 返回值:* 成功:0* 失败:-1* *********************************************/
int gettoaddress(int sockfd, struct mail *pmail)
{if (sockfd < 2){return -1;}char buf[128] = "";read(sockfd, buf, sizeof(buf) - 1);strcpy(pmail->recv, buf);printf("地址:%s\n", buf);return 0;
}
/************************************************* 函数名:int getbody(int sockfd, struct mail *pmail)* 功能:获取邮件信息中正文* 参数:* sockfd:套接字* pmail:用来存放邮件正文的结构体* 返回值:* 成功:0* 失败:-1* *********************************************/
int getbody(int sockfd, struct mail *pmail)
{if (sockfd < 2){return -1;}char buf[4096] = "";read(sockfd, buf, sizeof(buf) - 1);printf("body数据为:%s\n", buf);strcpy(pmail->raw, buf);read(sockfd, buf, sizeof(buf) - 1);return 0;
}
parsemail.h
#ifndef PARSEMAIL_H
#define PARSEMAIL_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include "common.h"
#include "base64.h"
#define sqlite3_databas_filename "/usr/mail/data.db" //数据库名称
#define sqlite3_table_filename "user" //表名称
int vernamepass(table_t usertable);
int parsemail(struct mail *pmail, struct subject_ctrl *subject,char *info,table_t *table);
#endif
parsemail.c
#include "parsemail.h"/************************************************* 函数名:int vernamepass(table_t usertable)* 功能:验证登录* 参数:* pmail:存放了邮件解析出的信息* subject:控制硬件的结构体* info:拼装邮件用到的缓存变量* table:其存放了用户名与密码* 返回值:* 成功:0* 失败:-1* *********************************************/
int vernamepass(table_t usertable)
{sqlite3 *ppDb; //数据库操作句柄if (sqlite3_open(sqlite3_databas_filename, &ppDb) != 0){printf("sqlite3_open error:%s\n", sqlite3_errmsg(ppDb));exit(-1);}//printf("本地<%s>数据库打开成功\n", sqlite3_databas_filename);char **pazResult; //用于存储数据返回的二维表格(降为打击)int pnRow; //行int pnColumn; //列char *pzErrmsg; //错误码int len;char login[1024] = "select * from user where 用户名 = '%s' and 密码 = '%s' ;";char loginbuf[1024] = "";sprintf(loginbuf, login, usertable.username, usertable.password);len = strlen(login);if (sqlite3_get_table(ppDb, loginbuf, &pazResult, &pnRow, &pnColumn, &pzErrmsg) != 0){printf("登录失败! sqlite3_get_table error:%s\n", pzErrmsg);return 0;}else{if (pnRow >= 1){sqlite3_close(ppDb);return 1;}else{sqlite3_close(ppDb);return 0;}}return -1;
}
/************************************************* 函数名:int parsemail(struct mail *pmail, struct subject_ctrl *subject, char *info, table_t *table)* 功能:解析邮件 进行邮件的组装* 参数:* pmail:存放了邮件解析出的信息* subject:控制硬件的结构体* info:拼装邮件用到的缓存变量* table:其存放了用户名与密码* 返回值:* 成功:0* 失败:-1* *********************************************/
int parsemail(struct mail *pmail, struct subject_ctrl *subject, char *info, table_t *table)
{char *p;sqlite3 *ppDb; //数据库操作句柄char **pazResult; //用于存储数据返回的二维表格(降为打击)int pnRow; //行int pnColumn; //列char *pzErrmsg; //错误码if (sqlite3_open(sqlite3_databas_filename, &ppDb) != 0){printf("拼接邮件时 数据库 打开失败!\n");exit(-1);}const char *update = "update user set 密码 = '%s' where 用户名 = '%s' ; \n";char updatebuf[1024] = "";/***************获取时间 用来拼接邮件************************/time_t t;FILE *fa;struct tm *tt;char *time_str;t = time(&t); //获取秒数tt = localtime(&t); //转换成本地时间结构体time_str = asctime(tt); //转换成字符串时间/********************************************************/char subjectbuf[1024] = "";char tempbuf[1024] = "";char username[50] = "";char password[50] = "";if (NULL == pmail || NULL == subject){return -1;}printf("%s\n", pmail->raw);const char *sub = "Subject:";char *start = strstr(pmail->raw, sub) + 9;if (NULL == start){return -1;}char *end = strstr(start, "\r\n") - 1;if (NULL == end){return -1;}int len = end - start + 1;char buf[128] = "";strncpy(buf, start, len);const char *command = strtok(buf, " ");if (NULL == command){return -1;}strcpy(subject->command, command);if (!strcmp(command, "8LED")){const char *blub = strtok(NULL, " ");subject->bulb = atoi(blub);const char *blub_ctrl = strtok(NULL, " ");subject->bulb_ctrl = atoi(blub_ctrl);sprintf(subjectbuf, "8LED %d %d OK\n", subject->bulb, subject->bulb_ctrl);}else if (!strcmp(command, "7SHU")){const char *num = strtok(NULL, " ");subject->signal = atoi(num);sprintf(subjectbuf, "7SHU %d OK\n", subject->signal);}else if (!strcmp(command, "MOTO")){const char *revo = strtok(NULL, " ");subject->revo = atoi(revo);sprintf(subjectbuf, "MOTO %d OK\n", subject->revo);}else if (!strcmp(command, "CHANGETABLE")){const char *sub1 = "filename=";char *start1 = strstr(pmail->raw, sub1);//table.txtif (start1 == NULL){sprintf(subjectbuf, "CHANGETABLE FAIL!!NO FILE\n");}else{strcpy(start1, start1 + 24);printf("\n附件信息为%s\n", start1);p = start1;while (*(p++) != '-');*(p - 1) = '\0';printf("\n附件信息为%s\n", start1);fa = fopen("/usr/mail/usertemp", "w+");if (fa == NULL){printf("账户缓存打开失败");exit(-1);}fwrite(start1, strlen(start1), 1, fa);fseek(fa, 0, SEEK_SET);while (fscanf(fa, "%s %s\n", username, password) != EOF){sprintf(updatebuf, update, password, username);printf("%s",updatebuf);if (sqlite3_get_table(ppDb, updatebuf, &pazResult, &pnRow, &pnColumn, &pzErrmsg) != 0){printf("执行sql语句失败! sqlite3_get_table error:%s\n", pzErrmsg);return 0;}else{printf("账号更新成功\n");}}sprintf(subjectbuf, "CHANGETABLE OK\n");}}else{sprintf(subjectbuf, "Parse command error!!!!!\n");//return;}sqlite3_close(ppDb);memset(pmail->raw, 0, sizeof(pmail->raw));/*********************拼接邮件***********************************/// Message-ID: <001101c93cc4$1ed2ae30$5400a8c0@hexlerforever>\r\n// From: %s <%s>\r\n// To: <%s>\r\n// Subject:%s \r\n OK// Date: Sun Nov 2 14:26:30 2008// MIME-Version: 1.0\r\n// Content-Type: multipart/alternative; \r\n// X-Priority: 3..X-MSMail-Priority: Normal\r\n// X-Mailer: Microsoft Outlook Express 6.00.2900.3138\r\n// X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.3198\r\n// \r\n// This is response of %s device!\r\nstrcpy(info, "Message-ID: <001101c93cc4$1ed2ae30$5400a8c0@hexlerforever>\r\n");sprintf(tempbuf, "From: Ubuntu1604 <192.168.206.129@qq.com>\r\n");strcat(info, tempbuf);sprintf(tempbuf, "To: %s <%s@qq.com>\r\n", table->username, table->username);strcat(info, tempbuf);subjectbuf[strlen(subjectbuf) - 1] = '\0';sprintf(tempbuf, "Subject:%s \r\n", subjectbuf);strcat(info, tempbuf);sprintf(tempbuf, "Date: %s", time_str);strcat(info, tempbuf);strcat(info, "MIME-Version: 1.0\r\nContent-Type: multipart/alternative;\r\n\
X-Priority: 3..X-MSMail-Priority: Normal\r\nX-Mailer: Microsoft Outlook Express 6.00.2900.3138\r\n\
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.3198\r\n\r\n");sprintf(tempbuf, "This is response of %s device!\r\n", table->username);strcat(info, tempbuf);return 0;
}
net.h
#ifndef NET_H
#define NET_H
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "common.h"
#include "base64.h"
#include "parsemail.h"
#include "mailrecv.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include "common.h"
#include "parsemail.h"
int handleconnection(int sockfd, struct mail *pmail,table_t *table);
void pop3Connection(int cfd, char *info,table_t *table,int letx);
int Socket(int domain, int type, int protocol);
void Bind(int sockfd, const char *ip, short Port);
void Listen(int sockfd, int backlog);
void Print_cid(const struct sockaddr_in *addr);
#endif
net.c
#include "net.h"/************************************************* 函数名:int handleconnection(int cfd, struct mail *pmail, table_t *table)* 功能:SMTP服务 锁步流程* 参数:* cfd:套接字* pmail:解析邮件内容后 存放的结构体* table:获取到用户名和密码之后存放的结构体* 返回值:* 成功:0* 失败:-1* *********************************************/
int handleconnection(int cfd, struct mail *pmail, table_t *table)
{char *bufa;if (cfd < 2 || NULL == pmail){return -1;}char *response220 = "220 192.168.206.132 ok\r\n";char *response250_HELO = "250-192.168.206.132\r\n250-PIPELINING\r\n250-SIZE 52428800\r\n250-AUTH LOGIN PLAIN\r\n250-AUTH=LOGIN\r\n250-MAILCOMPRESS\r\n250 BITMIME\r\n";char *response334_user = "334 VXNlcm5hbWU6\r\n";char *response334_pass = "334 UGFzc3dvcmQ6\r\n";char *response235 = "235 Authenticatin successful\r\n";char *response250_ok = "250 OK\r\n";char *response_354 = "354 End data with <CR><LF>.<CR><LF>\r\n";char *response_221 = "221 Bye\r\n";char buf[4096] = "";while (write(cfd, response220, strlen(response220))){if (read(cfd, buf, sizeof(buf) - 2) != -1){sleep(1);if (!strncmp(buf, "HELO", 4) || !strncmp(buf, "EHLO", 4)){//printf("读取到客户端 开始接收文件\n");break;}}}//写入250_HELOwrite(cfd, response250_HELO, strlen(response250_HELO));read(cfd, buf, sizeof(buf) - 2);//printf("登录验证 处理的字符串为%s\n", buf);if (strncmp(buf, "AUTH LOGIN", 10)){perror("AUTH LOGIN error");return -1;}//写入334_userwrite(cfd, response334_user, strlen(response334_user));//printf("获取用户名\n");if (getusername(cfd, table)){perror("getusername error");return -1;}//printf("获取密码\n");//写入334_passwrite(cfd, response334_pass, strlen(response334_pass));if (getpassword(cfd, table)){perror("getpassword error");return -1;}//写入235_okwrite(cfd, response235, strlen(response235));//printf("来源地址\n");写入250_okwrite(cfd, response250_ok, strlen(response250_ok));//当邮件是用户在客户端选择重发的时候 这里会增加一个REST字段 需要用到一个判断进行解决read(cfd, buf, sizeof(buf) - 1);if (strncmp(buf, "REST", 4)){strcpy(pmail->send, buf);//发送方地址已输入至结构体//已经输入到结构体//printf("地址:%s\n", buf);}else{write(cfd, response250_ok, strlen(response250_ok));getfromaddress(cfd, pmail);perror("getFromaddress error");return -1;}//写入250_okwrite(cfd, response250_ok, strlen(response250_ok));//printf("发送地址\n");if (gettoaddress(cfd, pmail)){perror("getToAddress error");return -1;}//写入250_okwrite(cfd, response250_ok, strlen(response250_ok));//printf("data附件数据\n");read(cfd, buf, sizeof(buf) - 1);//printf("\n附件数据%s\n", buf);//写入354write(cfd, response_354, strlen(response_354));//printf("body正文:\n");if (getbody(cfd, pmail)){perror("getbody error");return -1;}//写入250_okwrite(cfd, response250_ok, strlen(response250_ok));//printf("quit指令\n");read(cfd, buf, sizeof(buf) - 1);if (strncmp(buf, "QUIT", 4)){printf("接收到的quit指令 字符串部分为%s\n\n\n", buf);perror("QUIT error");return -1;}//printf("最后发送一个221\n\n");//写入221write(cfd, response_221, strlen(response_221));//close(cfd);return 0;
}/************************************************* 函数名:void pop3Connection(int cfd, char *info)* 功能:pop3服务 发送邮件* 参数:* cid:套接字* info:无用* table:用来存放用户名与密码的结构体* letx:信件数* 返回值:* 无* *********************************************/
void pop3Connection(int cid, char *info, table_t *table, int letx)
{char delfilename[50] = "rm ";char filename[100] = "";char *p;int fd;char buf[1024] = "";//+OK POP3 server readystrcpy(buf, "+OK POP3 mail server ready\r\n");write(cid, buf, strlen(buf));//printf("写入OK Pop3 cid完成\n");read(cid, buf, sizeof(buf) - 1);strcpy(buf, buf + 5);p = buf;do{if (*p == '\r')*p = '\0';} while (*(p++));strcpy(table->username, buf);//printf("读取到用户名信息为:%s\n", table->username);//+OK hexler is welcome herestrcpy(buf, "+OK\r\n");write(cid, buf, strlen(buf));//printf("写入OK\n");read(cid, buf, sizeof(buf) - 1);strcpy(buf, buf + 5);p = buf;do{if (*p == '\r')*p = '\0';} while (*(p++));strcpy(table->password, buf);//printf("读取到密码信息为:%s\n", table->password);while (vernamepass(*table) != 1);//OKstrcpy(buf, "+OK\r\n");write(cid, buf, strlen(buf));//printf("写入OK\n");read(cid, buf, sizeof(buf) - 1);//printf("\n客户机发来的信息%s\n", buf);//OK 1 300if (letx <= 0){//printf("没有邮件\n");strcpy(buf, "+OK 0 0\r\n");}else{//printf("有邮件\n");strcpy(buf, "+OK 1 300\r\n");}write(cid, buf, strlen(buf));//printf("写入OK 1 300 or OK 0 0\n");read(cid, buf, sizeof(buf) - 1);//printf("\n客户机发来的信息%s\n", buf);//OK 1 message\r\n1 300\r\n.\r\nif (letx <= 0){strcpy(buf, "+OK 0 message\r\n0 0\r\n.\r\n");}else{strcpy(buf, "+OK 1 message\r\n1 300\r\n.\r\n");}write(cid, buf, strlen(buf));//printf("写入OK 1 message\n");read(cid, buf, sizeof(buf) - 1);//printf("\n客户机发来的信息%s\n", buf);//OK 120 octets\r\nstrcpy(buf, "+OK 120 octets\r\n");write(cid, buf, strlen(buf));//printf("写入OK 120 octets\n");//写入邮件信息//printf("这里接收到的邮件信息:\n%s", info);if (letx <= 0){//printf("没有邮件\n");strcpy(buf, "+OK 0 0\r\n");}else{sprintf(filename, "/usr/mail/%s/%d%s", "letter", letx, table->username);fd = open(filename, O_RDWR | O_CREAT, 0666);if (fd <= 0){perror("写入邮件信息 文件打开失败:");exit(-1);}strcat(delfilename, filename);printf("\n%s\n", delfilename);system(delfilename);}read(fd, buf, 1024);//printf("%s读取到的文件内容为:%s\n", filename, buf);write(cid, buf, strlen(buf));//printf("写入邮件\n");memset(buf, 0, sizeof(buf));//写入结束符strcpy(buf, "\r\n.\r\n");write(cid, buf, strlen(buf));//printf("写入rn\n");read(cid, buf, sizeof(buf) - 1);//printf("\n客户机发来的信息%s\n", buf);//OKstrcpy(buf, "+OK\r\n");write(cid, buf, strlen(buf));//printf("写入OK\n");read(cid, buf, sizeof(buf) - 1);//printf("\n客户机发来的信息%s\n", buf);//OKstrcpy(buf, "+OK\r\n");write(cid, buf, strlen(buf));//printf("写入OK\n");
}
/************************************************* int Socket(int domain, int type, int protocol)* 功能:建立socket套接字对象* 参数:* domain:域:用作基于什么类型操作* Name Purpose Man page* AF_UNIX, AF_LOCAL 局部通信 unix(7) 重点* AF_INET IPv4网络协议 ip(7) 重点* AF_INET6 IPv6网络协议 ipv6(7) 重点* AF_IPX IPX - Novell协议* AF_NETLINK 内核用户界面设备 netlink(7)* AF_X25 ITU-T X.25 / ISO-8208协议 x25(7)* AF_AX25 业余无线电AX.25协议* AF_ATMPVC 访问原始ATM pvc* AF_APPLETALK 可路由协议组 ddp(7)* AF_PACKET 低层包接口 packet(7)* AF_ALG 内核加密API接口* type:套接字类型* SOCK_STREAM:流式套接字 唯一对应 TCP协议* SOCK_DGRAM:数据报套接字 唯一对应 UDP协议* SOCK_RAW:原始套接字* protocol:根据套接字类型,一般默认填0,如果式原始套接字等则需要* 返回值:* 成功:返回特殊的文件描述符* 失败:-1,且errno存储错误类型* *********************************************/
int Socket(int domain, int type, int protocol)
{int sid = socket(domain, type, protocol);if (sid < 0){perror("socket:");exit(-1);}return sid;
}
/************************************************* 函数名:void Bind(int sockfd, const char *ip, short Port)* 功能:为任务绑定ip和端口号* 参数:* sockfd:通过socket函数拿到的文件特殊描述符* addr:struct sockaddr的结构体变量的首地址* addrlen:struct sockaddr的结构体变量的长度* 返回值:* 成功:0* 失败:-1,并且填写errno* *********************************************/
void Bind(int sockfd, const char *ip, short Port)
{struct sockaddr_in addr;addr.sin_family = AF_INET | SO_REUSEADDR;addr.sin_port = htons(Port);addr.sin_addr.s_addr = inet_addr(ip);if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1){perror("bind:");exit(-1);}
}
/************************************************* 函数名:void Listen(int sockfd, int backlog)* 功能:监听套接字,将主动套接字变成被动套接字* 参数:* sockfd:通过socket函数拿到的文件特殊描述符* backlog:定义了队列的最大长度,最多客户端同时访问,一般填5* 如果一个连接请求当队列已满时到达,客户端可能会收到一个错误指示ECO* NNREFUSED或,如果底层 协议支持重传时,请求可能会被忽略,以便稍* 后重试连接成功。* 返回值:* 成功:0* 失败:-1,并且填写errno* *********************************************/
void Listen(int sockfd, int backlog)
{if (listen(sockfd, backlog) == -1){perror("listen:");exit(-1);}
}
/************************************************* 函数名:Print_cid(const struct sockaddr_in *addr)* 功能:输出套接字* 参数:* addr:套接字地址* 返回值:* 无* *********************************************/
void Print_cid(const struct sockaddr_in *addr)
{printf("类型是%s\n", addr->sin_family == AF_INET ? "AFINET" : "AF_INET6");printf("ip地址为:%s\n端口号:%d\n", inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
}
下面解码的这个功能不是我写的,我直接用的,上面所有的功能都基本上是我写的吧,注释也都写好了,很容易就能看懂,分享不易,希望多多支持。
base64.h
#ifndef BASE64_H
#define BASE64_H
#include <stdio.h>
#include <string.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define BASE64_PAD64 '='
char* base64_encode(const char *data);
char* base64_decode(const char *bdata);
#endif
base64.c
#include"base64.h"#define BASE64_PAD64 '='unsigned int base64_alphabet[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I','J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R','S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a','b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j','k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's','t', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1','2', '3', '4', '5', '6', '7', '8', '9', '+','/'};unsigned int base64_suffix_map[256] = {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28,29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};static int cmove_bits(unsigned char src, unsigned lnum, unsigned rnum) {src <<= lnum; src >>= rnum;return src;}char* base64_encode(const char *data) {char *ret, *retpos;int m, padnum = 0, retsize, dlen = strlen(data);if(dlen == 0) return NULL;/* Account the result buffer size and alloc the memory for it. */if((dlen % 3) != 0)padnum = 3 - dlen % 3;retsize = (dlen + padnum) + ((dlen + padnum) * 1/3) + 1;if((ret = malloc(retsize)) == NULL) return NULL;retpos = ret;/* Starting to convert the originality characters to BASE64 chracaters. Converting process keep to 4->6 principle. */for(m = 0; m < (dlen + padnum); m += 3) {/* When data is not suffice 24 bits then pad 0 and the empty place pad '='. */*(retpos) = base64_alphabet[cmove_bits(*data, 0, 2)];if(m == dlen + padnum - 3 && padnum != 0) { /* Whether the last bits-group suffice 24 bits. */if(padnum == 1) { /* 16bit need pad one '='. */*(retpos + 1) = base64_alphabet[cmove_bits(*data, 6, 2) + cmove_bits(*(data + 1), 0, 4)];*(retpos + 2) = base64_alphabet[cmove_bits(*(data + 1), 4, 2)];*(retpos + 3) = BASE64_PAD64;} else if(padnum == 2) { /* 8bit need pad two'='. */*(retpos + 1) = base64_alphabet[cmove_bits(*data, 6, 2)];*(retpos + 2) = BASE64_PAD64;*(retpos + 3) = BASE64_PAD64;}} else { /* 24bit normal. */*(retpos + 1) = base64_alphabet[cmove_bits(*data, 6, 2) + cmove_bits(*(data + 1), 0, 4)];*(retpos + 2) = base64_alphabet[cmove_bits(*(data + 1), 4, 2) + cmove_bits(*(data + 2), 0, 6)];*(retpos + 3) = base64_alphabet[*(data + 2) & 0x3f];}retpos += 4;data += 3;}ret[retsize - 1] =0;return ret;}char* base64_decode(const char *bdata) {char *ret = NULL, *retpos;int m, padnum = 0, retsize, bdlen = strlen(bdata);if(bdlen == 0) return NULL;if(bdlen % 4 != 0) return NULL;/* Whether the data have invalid base-64 characters? */for(m = 0; m < bdlen; ++m) {if(bdata[m] != BASE64_PAD64 && base64_suffix_map[(int)(bdata[m])] == 255)goto LEND;}/* Account the output size. */if(bdata[bdlen - 1] == '=') padnum = 1;if(bdata[bdlen - 1] == '=' && bdata[bdlen - 2] == '=') padnum = 2;retsize = (bdlen - 4) - (bdlen - 4) / 4 + (3 - padnum) + 1;ret = malloc(retsize);if(ret == NULL) return NULL;retpos = ret; /* Begging to decode. */for(m = 0; m < bdlen; m += 4) {*retpos = cmove_bits(base64_suffix_map[(int)(*bdata)], 2, 0) + cmove_bits(base64_suffix_map[(int)(*(bdata + 1))], 0, 4);if(m == bdlen - 4 && padnum != 0) { /* Only deal with last four bits. */if(padnum == 1) /* Have one pad characters, only two availability characters. */*(retpos + 1) = cmove_bits(base64_suffix_map[(int)(*(bdata + 1))], 4, 0) + cmove_bits(base64_suffix_map[(int)(*(bdata + 2))], 0, 2);/*Have two pad characters, only two availability characters.if(padnum == 2) { }*/retpos += 3 - padnum;} else {*(retpos + 1) = cmove_bits(base64_suffix_map[(int)(*(bdata + 1))], 4, 0) + cmove_bits(base64_suffix_map[(int)(*(bdata + 2))], 0, 2);*(retpos + 2) = cmove_bits(base64_suffix_map[(int)(*(bdata + 2))], 6, 0) + base64_suffix_map[(int)(*(bdata + 3))];retpos += 3;}bdata += 4;}ret[retsize - 1] = 0;LEND: return ret;}
这篇关于【Hexler】Ubuntu下的简单Smtp Pop3邮件收发服务器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!