環境: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; }