2011-09-25 50 views
1

我發現下面的功能,可發送郵件:如何通過套接字發送結構?

bool sendmail(char * smtpserver, char * from, char * to, char * subject, char * msg) 
{ 
int   iProtocolPort  = 0; 
char  szSmtpServerName[64] = ""; 
char  szToAddr[64]   = ""; 
char  szFromAddr[64]  = ""; 
char  szBuffer[4096]  = ""; 
char  szLine[255]   = ""; 
char  szMsgLine[255]  = ""; 
SOCKET  hServer; 
WSADATA  WSData; 
LPHOSTENT lpHostEntry; 
LPSERVENT lpServEntry; 
SOCKADDR_IN SockAddr; 

// Load command-line args 
lstrcpyA(szSmtpServerName, smtpserver); 
lstrcpyA(szToAddr, to); 
lstrcpyA(szFromAddr, from); 

// Attempt to intialize WinSock (1.1 or later) 
if (WSAStartup(MAKEWORD(VERSION_MAJOR, VERSION_MINOR), &WSData)) 
{  
    printf("\nCannot find Winsock v%d.%d or later", VERSION_MAJOR, VERSION_MAJOR);  
    return false; 
} 
// Lookup email server's IP address. 
lpHostEntry = gethostbyname(szSmtpServerName); 
if (!lpHostEntry) 
{  
    printf("\nCannot find SMTP mail server %s", szSmtpServerName);  
    return false; 
} 

// Create a TCP/IP socket, no specific protocol 
hServer = socket(PF_INET, SOCK_STREAM, 0); 
if (hServer == INVALID_SOCKET) 
{  
    printf("\nCannot open mail server socket!");  
    return false; 
} 

// Get the mail service port 
lpServEntry = getservbyname("mail", 0); 

// Use the SMTP default port if no other port is specified 
if (!lpServEntry) iProtocolPort = htons(IPPORT_SMTP); 
else iProtocolPort = lpServEntry->s_port; 

// Setup a Socket Address structure 
SockAddr.sin_family = AF_INET; 
SockAddr.sin_port = iProtocolPort; 
SockAddr.sin_addr = *((LPIN_ADDR)*lpHostEntry->h_addr_list); 

// Connect the Socket 
if (connect(hServer, (PSOCKADDR) &SockAddr, sizeof(SockAddr))) 
{  
    printf("\nError connecting to Server socket!"); 
    return false; 
} 

// Receive initial response from SMTP server 
Check(recv(hServer, szBuffer, sizeof(szBuffer), 0), "recv() Reply"); 

// Send HELO server.com 
sprintf_s(szMsgLine, "HELO %s%s", smtpserver, CRLF); 
Check(send(hServer, szMsgLine, strlen(szMsgLine), 0), "send() HELO"); 
Check(recv(hServer, szBuffer, sizeof(szBuffer), 0), "recv() HELO"); 

// Send MAIL FROM: <[email protected]> 
sprintf_s(szMsgLine, "MAIL FROM:<%s>%s", from, CRLF); 
Check(send(hServer, szMsgLine, strlen(szMsgLine), 0), "send() MAIL FROM"); 
Check(recv(hServer, szBuffer, sizeof(szBuffer), 0), "recv() MAIL FROM"); 

// Send RCPT TO: <[email protected]>  
sprintf_s(szMsgLine, "RCPT TO:<%s>%s", to, CRLF);  
Check(send(hServer, szMsgLine, strlen(szMsgLine), 0), "send() RCPT TO");  
Check(recv(hServer, szBuffer, sizeof(szBuffer), 0), "recv() RCPT TO"); 

// Send DATA 
sprintf_s(szMsgLine, "DATA%s", CRLF); 
Check(send(hServer, szMsgLine, strlen(szMsgLine), 0), "send() DATA"); 
Check(recv(hServer, szBuffer, sizeof(szBuffer), 0), "recv() DATA"); 

// Send Subject 
sprintf_s(szBuffer, "Subject: %s\n", subject); 
Check(send(hServer, szBuffer, strlen(szBuffer), 0), "send() Subject"); 

//Send From 
sprintf_s(szBuffer, "From: %s\n", from); 
Check(send(hServer, szBuffer, strlen(szBuffer), 0), "send() From"); 

//Send To 
sprintf_s(szBuffer, "To: %s\n\n", to); 
Check(send(hServer, szBuffer, strlen(szBuffer), 0), "send() To"); 

//Check(send(hServer, szMsgLine, strlen(szMsgLine), 0), "send() Attachment"); 
sprintf_s(szMsgLine, "%s%s", msg, CRLF); 
Check(send(hServer, szMsgLine, strlen(szMsgLine), 0), "send() message-line"); 

// Send blank line and a period 
sprintf_s(szMsgLine, "%s.%s", CRLF, CRLF); 
Check(send(hServer, szMsgLine, strlen(szMsgLine), 0), "send() end-message"); 
Check(recv( hServer, szBuffer, sizeof(szBuffer), 0), "recv() end-message"); 

// Send QUIT 
sprintf_s(szMsgLine, "QUIT%s", CRLF); 
Check(send(hServer, szMsgLine, strlen(szMsgLine), 0), "send() QUIT"); 
Check(recv(hServer, szBuffer, sizeof(szBuffer), 0), "recv() QUIT"); 

// Close server socket and prepare to exit. 
closesocket(hServer); 

WSACleanup(); 

return true; 
} 

我想提出一個SQL查詢,我想將結果發送到電子郵件,但結果可能是多行。所以我不知道,我怎麼能一次發送整個結果。 SQL查詢的結果將存儲在一個結構中(但如果有人有更好的idee,那麼我在聽:))。所以我的問題是,如果有一種方法發送這個結構在電子郵件?或者,我怎樣才能發送我在電子郵件中得到的每一行?

謝謝!

+0

你可以先解決你的'的sendmail()'函數,以便它可以發送郵件長度超過255個字符?一旦你完成了這些工作,其餘的工作就像將你的結構轉換成你想在電子郵件中發送的字符串格式一樣簡單。 – aroth

+0

@aroth:所有我需要做的就是用大一號的聲明szMsgLine。那沒問題。但是,我如何發送我的結構一次?我應該只是連接線,那就是它? – kampi

+3

@kampi - 是的,你有你的結構的內容轉換成C字符串轉換併發送這些字符串。這是因爲另一端的電子郵件處理程序不知道如何解釋你的結構。一般規則是結構在機器邊界上永遠不可移植。 –

回答

0

在你想給你的結構的一面:

// All sorts of initializations and stuff 
memcpy(yourbuffer,&yourstructure,sizeof(yourbuffer)); 

在另一側:

// Trivial stuff like receiving your buffer :-) 
memcpy(&yourstructure,yourbuffer,sizeof(yourstructure)); 
0

要回答你的第一個問題,如果你想通過套接字發送結構,首先你必須序列化。特別是,目標機器上的整數字節可能不是相同的順序。有很多序列化數據的協議,例如ASN.1和JSON。對於C結構,你最好使用諸如msgpack或protobufs之類的東西。在序列化數據之後,你有一個字節數組,它可以簡單地通過套接字一次發送一個數據塊。一般情況下,也將具有圍繞纏繞的協議,該協議可以是簡單的:

SENDBUF 437\r\n 
GSUOHD*)*IHENHD{@DNJDPOJDPJONK:ND{[email protected] LDK?ND(G(OBDO*U|GR(G(DIU:OBD 

基本上它是一個命令串,隨後的字節在該包,接着回車,換行數目。這是HTTP,memcache和其他許多人使用的典型協議樣式。換行符後,您會在輸入緩衝區的末尾收集下一個n字節(示例中爲437)。由於許多結構將多個數據包,你可能已經BEGIN和END命令,或者你可以簡單地關閉套接字標記一個結構的結束。

接收過程將收集字節,直到該結構的端部,然後反序列化。

如果您使用類似ZeroMQ的庫,這將簡化套接字處理,但您仍然必須處理序列化和反序列化結構。