环境:xp系统,vc6.0、c语言c++
这里是代码的草稿,本来设计的结构跟如今撸出来的结构相差比较大windows
实现的部分:服务器
smtp协议,能够完成最简邮件格式的发送,收件人能够正常收到socket
base64编码,能够完成对任意长度的字符串进行base64编码tcp
base64解码,只是完成了对单个字节解码函数
pop协议,只是完成了基本的服务器交互指令,对于data部分的接收没有实现oop
个人想法是摸索阶段的代码必定不会使用c++,进行整合优化的时候会考虑使用c++封装测试
还有看的时候,可能会感受代码比较乱,若是愿意的话,能够给我一些建议优化
#include <Winsock2.h> #include <stdio.h> #include <windows.h>
#pragma comment(lib,"ws2_32.lib")
#define PORTPOP 110 #define PORTSMTP 25 #define BUFF_BASE64 1024*1024*4 //开辟4M的base64编码的存储区,2M发送的数据,2M接收的数据
char *buff_begin;//缓冲区的起始指针 unsigned long num_now;//缓冲区当前字节数 char *point_now;//指向当前缓冲区的可用部分
struct base64{ char result;//base64加密后的结果 char residue;//原数据剩下的部分 int number;//位移的位数 };
char base64_char[64]={'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','+','/',};
int chartonumber(base64 *data); //编码:数字转换为对应字母 int transformtobase64(base64 *data); //编码:对单字节编码 int transformstring(char *strings); //编码:对字符串编码
//套接字是否已经链接 int condition_pop3=0; int tcp_pop(SOCKET pop,sockaddr_in saddr,char *r_buffer,char *s_buffer); int tcp_smtp(char *r_buffer,char *s_buffer);
char *name="servertss"; //用户名 char *pasw="12345zxcvb";//密码
char *capa="CAPA"; char *user="USER";//用户名 char *pass="PASS";//密码 char *apop="APOP";//指定邮箱和MD5摘要串 char *stat="STAT";//请求邮件总数和总字节数 char *uidl="UIDL";//返回邮件的惟一标识符 char *list="LIST";//返回邮件数量和每一个邮件的大小 char *retr="RETR";//返回由参数标识的邮件的所有文本 char *dele="DELE";//服务器将由参数标识的邮件标记为删除 char *rset="RSET";//服务器将重置全部标记为删除的邮件,用于撤销DELE命令 char *top="TOP";//服务器将返回由参数标识的邮件前n行内容,n必须是正整数 char *noop="NOOP";//服务器返回一个确定的响应 char *quit="QUIT";//结束会话
char *ok="+OK";//服务器确认标识 char crlf[2]={'\r','\n'};//结束标志
char *ehlo="EHLO";//开始SMTP会话 char *auth="AUTH"; char *login="LOGIN"; char *mail="MAIL";//邮件开始 char *from="FROM";//发件方地址 char *rcpt="RCPT";//收件方地址 char *data="DATA";//邮件正文开始 char *vrfy="VRFY";//用于验证指定的用户/邮箱是否存在 char *expn="EXPN";//验证给定的邮箱列表是否存在,扩充邮箱列表,常被禁用 char *help="HELP";//查询服务器支持什么命令
int senddata(char *begin);
int main() { WORD wVersionRequested; WSADATA wsaData; wVersionRequested=MAKEWORD(2,2); int err=WSAStartup(wVersionRequested,&wsaData); if(err!=0) { printf("WSAStartup函数加载失败\n"); return 0; }
buff_begin=(char *)malloc(BUFF_BASE64); if(!buff_begin) return 0; num_now=0; point_now=buff_begin;
char request[512];//客户端请求缓冲 char respond[512];//服务器回应缓冲 //memset(request,'\0',512); //memset(respond,'\0',512);
sockaddr_in saddr_pop; saddr_pop.sin_family=AF_INET; saddr_pop.sin_port=htons(PORTPOP); saddr_pop.sin_addr.s_addr= inet_addr("123.125.50.29"); SOCKET client_pop; client_pop=socket(AF_INET,SOCK_STREAM,0);
/* char *s="这是一份测试邮件"; transformstring(s); for(int i=0;i<num_now;i++) { printf("%c",*(buff_begin+i)); } printf("\n"); */ int n=10; while(n) { tcp_smtp(request,respond); Sleep(30000); n--; } /* int ii=senddata(buff_begin); printf("%d",ii); for(int i=0;i<ii;i++) { printf("%c",*(buff_begin+i)); } */ /* tcp_pop(client_pop,saddr_pop,request,respond);
bool brk=1; while(brk)//主循环会一直对是否有新邮件进行查询 { Sleep(5000); } */ WSACleanup(); return 1; }
//POP链接 int tcp_pop(SOCKET pop,sockaddr_in saddr,char *r_buffer,char *s_buffer) { int con=connect(pop,(struct sockaddr *)&saddr,sizeof(saddr)); if(con==0) printf("TCP已经链接\n"); else return 0; //TCP链接完成以后会受到服务的第一次确认 memset(r_buffer,'\0',512); int rec=recv(pop,r_buffer,512,0); printf("%s\n",r_buffer);
//CAPA指令 memset(s_buffer,'\0',512); memcpy(s_buffer,capa,4); memcpy(s_buffer+4,crlf,2); printf("%s\n",s_buffer); send(pop,s_buffer,6,0);
//CAPA指令以后接收服务器回应 memset(r_buffer,'\0',512); rec=recv(pop,r_buffer,512,0); printf("%s",r_buffer);
//USER指令 memset(s_buffer,'\0',512); memcpy(s_buffer,user,4); *(s_buffer+4)=' '; memcpy(s_buffer+5,name,9); memcpy(s_buffer+14,crlf,2); printf("%s\n",s_buffer); send(pop,s_buffer,16,0);
//USER指令以后接收服务器回应 memset(r_buffer,'\0',512); rec=recv(pop,r_buffer,512,0); printf("%s",r_buffer);
//PASS指令 memset(s_buffer,'\0',512); memcpy(s_buffer,pass,4); *(s_buffer+4)=' '; memcpy(s_buffer+5,pasw,10); memcpy(s_buffer+15,crlf,2); printf("%s\n",s_buffer); send(pop,s_buffer,17,0);
//PASS指令以后,服务器返回邮箱邮件总数 memset(r_buffer,'\0',512); rec=recv(pop,r_buffer,512,0); printf("%s",r_buffer);
//STAT指令 memset(s_buffer,'\0',512); memcpy(s_buffer,stat,4); memcpy(s_buffer+4,crlf,2); printf("%s\n",s_buffer); send(pop,s_buffer,6,0);
//STAT指令以后接收服务器回应,请求邮件总数和总字节数 memset(r_buffer,'\0',512); rec=recv(pop,r_buffer,512,0); printf("%s",r_buffer);
//UIDL指令 memset(s_buffer,'\0',512); memcpy(s_buffer,uidl,4); memcpy(s_buffer+4,crlf,2); printf("%s\n",s_buffer); send(pop,s_buffer,6,0);
//UIDL指令以后接收服务器回应,返回邮件的惟一标识符 memset(r_buffer,'\0',512); rec=recv(pop,r_buffer,512,0); printf("%s",r_buffer);
//LIST指令 memset(s_buffer,'\0',512); memcpy(s_buffer,list,4); memcpy(s_buffer+4,crlf,2); printf("%s\n",s_buffer); send(pop,s_buffer,6,0);
//LIST指令以后接收服务器回应,返回邮件数量和每一个邮件的大小 memset(r_buffer,'\0',512); rec=recv(pop,r_buffer,512,0); printf("%s",r_buffer);
//QUIT指令 memset(s_buffer,'\0',512); memcpy(s_buffer,quit,4); memcpy(s_buffer+4,crlf,2); printf("%s\n",s_buffer); send(pop,s_buffer,6,0);
//QUIT指令以后接收服务器回应,返回邮件数量和每一个邮件的大小 memset(r_buffer,'\0',512); rec=recv(pop,r_buffer,512,0); printf("%s",r_buffer); return 1; }
//SMTP链接 int tcp_smtp(char *r_buffer,char *s_buffer) { sockaddr_in saddr_smtp; saddr_smtp.sin_family=AF_INET; saddr_smtp.sin_port=htons(PORTSMTP); saddr_smtp.sin_addr.s_addr= inet_addr("123.125.50.134"); SOCKET smtp; smtp=socket(AF_INET,SOCK_STREAM,0);
int con=connect(smtp,(struct sockaddr *)&saddr_smtp,sizeof(saddr_smtp)); if(con==0) printf("TCP已经链接\n"); else { return 0; }
//TCP链接完成以后会受到服务的第一次确认 memset(r_buffer,'\0',512); int rec=recv(smtp,r_buffer,512,0); printf("%s",r_buffer);
//EHLO指令 memset(s_buffer,'\0',512); memcpy(s_buffer,ehlo,4); memcpy(s_buffer+5,name,9); memcpy(s_buffer+14,crlf,2); printf("%s",s_buffer); send(smtp,s_buffer,16,0);
//EHLO指令以后接收服务器回应 memset(r_buffer,'\0',512); rec=recv(smtp,r_buffer,512,0); printf("%s",r_buffer);
//AUTH指令 memset(s_buffer,'\0',512); memcpy(s_buffer,auth,4); *(s_buffer+4)=' '; memcpy(s_buffer+5,login,5); memcpy(s_buffer+10,crlf,2); printf("%s",s_buffer); send(smtp,s_buffer,12,0);
//AUTH指令以后接收服务器回应 memset(r_buffer,'\0',512); rec=recv(smtp,r_buffer,512,0); printf("%s",r_buffer);
//USER memset(s_buffer,'\0',512); memcpy(s_buffer,"c2VydmVydHNz",12); memcpy(s_buffer+12,crlf,2); printf("%s",s_buffer); send(smtp,s_buffer,14,0);
//USER以后接收服务器回应 memset(r_buffer,'\0',512); rec=recv(smtp,r_buffer,512,0); printf("%s",r_buffer);
//PASS memset(s_buffer,'\0',512); memcpy(s_buffer,"MTIzNDV6eGN2Yg==",16); memcpy(s_buffer+16,crlf,2); printf("%s",s_buffer); send(smtp,s_buffer,18,0);
//PASS以后 memset(r_buffer,'\0',512); rec=recv(smtp,r_buffer,512,0); printf("%s",r_buffer);
//MAIL指令 memset(s_buffer,'\0',512); memcpy(s_buffer,mail,4); *(s_buffer+4)=' '; memcpy(s_buffer+5,"FROM: <); memcpy(s_buffer+30,crlf,2); printf("%s\n",s_buffer); send(smtp,s_buffer,32,0);
//MAIL指令以后 memset(r_buffer,'\0',512); rec=recv(smtp,r_buffer,512,0); printf("%s",r_buffer);
//RCPT指令 memset(s_buffer,'\0',512); memcpy(s_buffer,rcpt,4); *(s_buffer+4)=' '; memcpy(s_buffer+5,"TO: <); memcpy(s_buffer+28,crlf,2); printf("%s",s_buffer); send(smtp,s_buffer,30,0);
//RCPT指令以后 memset(r_buffer,'\0',512); rec=recv(smtp,r_buffer,512,0); printf("%s",r_buffer);
//DATA指令 memset(s_buffer,'\0',512); memcpy(s_buffer,data,4); memcpy(s_buffer+4,crlf,2); printf("%s",s_buffer); send(smtp,s_buffer,6,0);
//DATA指令以后 int ii=senddata(buff_begin); send(smtp,buff_begin,ii,0);
memset(r_buffer,'\0',512); rec=recv(smtp,r_buffer,512,0); printf("%s",r_buffer);
//QUIT指令 memset(s_buffer,'\0',512); memcpy(s_buffer,quit,4); memcpy(s_buffer+4,crlf,2); printf("%s\n",s_buffer); send(smtp,s_buffer,6,0);
//QUIT指令以后接收服务器回应,返回邮件数量和每一个邮件的大小 memset(r_buffer,'\0',512); rec=recv(smtp,r_buffer,512,0); printf("%s",r_buffer);
closesocket(smtp); return 1; }
//在2M缓冲区组建须要发送的数据 int senddata(char *begin) { int num=0; memcpy(begin,"Date: Sat,8 Mar 2014 22:36:04 +0800 (CST)",41); memcpy(begin+41,crlf,2); num+=43;
memcpy(begin+num,"From: \"" <); memcpy(begin+num+45,crlf,2); num+=45+2;
memcpy(begin+num,"To: servertss <); memcpy(begin+num+33,crlf,2); num+=33+2;
memcpy(begin+num,"Subject: =?GB2312?B?YysrtcTEx7G+yunE47fF1NrExMDvwcs=?=",54); memcpy(begin+num+54,crlf,2); num+=54+2;
memcpy(begin+num,"Mime-Version: 1.0",17); memcpy(begin+num+17,crlf,2); num+=17+2;
memcpy(begin+num,"Message-ID: <); memcpy(begin+num+43,crlf,2); num+=43+2;
memcpy(begin+num,"Content-Type: multipart/alternative;",36); *(begin+num+36)='\n'; *(begin+num+37)='\t'; memcpy(begin+num+36+2,"boundary=\"----=_001_NextPart674370231387_=----\"",48); memcpy(begin+num+36+2+48,crlf,2); num+=36+2+48+2;
memcpy(begin+num,crlf,2); num+=2;
memcpy(begin+num,"------=_001_NextPart674370231387_=----",38); memcpy(begin+num+38,crlf,2); num+=38+2;
memcpy(begin+num,"Content-Type: text/plain;",25); *(begin+num+25)='\n'; *(begin+num+26)='\t'; memcpy(begin+num+25+2,"charset=\"GB2312\"",16); memcpy(begin+num+25+2+16,crlf,2); num+=25+2+16+2;
memcpy(begin+num,"Content-Transfer-Encoding: base64",33); memcpy(begin+num+33,crlf,2); *(begin+num+33+2)='\n'; num+=33+2+1;
memcpy(begin+num,"CgoKYysrtcTEx7G+yunE47fF1NrExMDvwcsKy9m2yLjmy9/O0goK",52); num+=52;
memcpy(begin+num,crlf,2); num+=2;
memcpy(begin+num,"------=_001_NextPart674370231387_=----",38); memcpy(begin+num+38,crlf,2); num+=38+2;
memcpy(begin+num,crlf,2); *(begin+num+2)='.'; memcpy(begin+num+2+1,crlf,2); num+=2+1+2;
return num; }
//接收到服务器的消息,须要进行检验是否为“+OK”和其余确认标识,以及后面的字符集 /* int check_id(char *buff) { char id[4]; char characters[500]; memset(id,'\0',4); memset(characters,'\0',500);
int i=0; for(i=0;i<4;i++) { id[i]=*(buff+i); i++; } switch(id) { case "+OK": break; } return 1; } */
//对字符串进行base64编码 int transformstring(char *strings) { int num=0; //记录字节数目 int buf=0; //临时单字节存储 base64 buf_transfer; //base64转换的中转 memset(&buf_transfer,'\0',sizeof(buf_transfer)); buf_transfer.result=*strings; buf_transfer.number=0;
while(buf_transfer.result!='\0')//字符串结束,则程序结束 { if((0<=buf)&&(buf<6)) { buf=transformtobase64(&buf_transfer); memcpy(point_now,&(buf_transfer.result),1); num++; buf_transfer.result=*(strings+num); } else { if(buf==6) { *point_now=base64_char[(unsigned int)buf_transfer.residue]; buf_transfer.number=0; buf_transfer.residue='\0'; buf=0; } else return buf; } point_now=point_now+1; num_now++; }
if(buf_transfer.residue) { *point_now=base64_char[(unsigned int)(buf_transfer.residue<<(6-buf_transfer.number))]; point_now++; num_now++; } buf=num%3; switch(buf) { case 0: break; case 1: memset(point_now,'=',2); point_now=point_now+2; num_now=num_now+2; break; case 2: *point_now='='; point_now++; num_now++; break; } return num; }
int transformtobase64(base64 *data)//对单字节数据进行base64编码 { if(data->number<0) return -1; if(data->number>6) return 8;
char buf='\0',back='\0'; buf=data->residue<<(6-data->number); back=data->result>>(2+data->number); buf=back^buf; buf&=63;
back='\0'; back=data->result<<(6-data->number); data->residue=back>>(6-data->number);
data->result=base64_char[(unsigned int)buf]; data->residue&=63;
data->number=2+data->number;
return data->number; }
//对字符串进行base64解码 int transformbase64(char *strings) { return 1; } int base64totransform(base64 *data)//对单字节数据进行base64解码 { if(data->number<0) return -1; if(data->number>6) return 8;
if(!chartonumber(data))//转换为6位 return 0;
char buf='0',back='0'; buf=data->residue<<(8-data->number); if(data->number<3) { back=data->result; data->number+=6; } else{ if(data->number<9) { back=data->result>>(data->number-2); data->result=data->result<<(10-data->number); data->residue=data->result>>(10-data->number); data->number=data->number-2; data->result=buf^back; } } data->residue=back^buf;
if(data->number>7) { data->result=data->residue; data->residue='0'; data->number=0; }
return data->number; } int chartonumber(base64 *data) { //65-90:A-Z //97-122:a-z //48-57:0-9 //43,47:+,/ int cod=0; if(64<(int)(data->result)&&91>(int)(data->result)) { cod=1; data->result=char((int)(data->result)-65); } if(96<(int)(data->result)&&123>(int)(data->result)) { cod=1; data->result=char((int)(data->result)-97+26); } if(47<(int)(data->result)&&58>(int)(data->result)) { cod=1; data->result=char((int)(data->result)-48+52); } if(43==(int)(data->result)) { cod=1; data->result=0x2B; } if(47==(int)(data->result)) { cod=1; data->result=0x2F; } if(cod) return 1; else return 0; }