相信大家都有過被C語言網(wǎng)絡編程所支配的恐懼吧?其實,小編在剛剛學習這方面的知識的時候也有這樣的感受,并且所有的資料都是從網(wǎng)絡尋找的,但是,現(xiàn)在你們不同了,因為這篇文章將會帶你們一步步地,寫出你們第一個使用SMTP協(xié)議來發(fā)送郵件的C語言程序,這個和小編剛學習的時候可不同呀!
文章末尾有總結,這是精髓哦
首先,這篇文章不是講理論的文章,而是讓你們動手實踐的文章,目的在于讓各位看官能動手寫出能編譯成功、能成功運行、能成功發(fā)送郵件的C語言程序,這篇文章不會涉及太多的理論知識,并且代碼也沒有經(jīng)過特別的封裝,旨在讓各位看官能編寫出這個程序,所以看官跟著文章動手做就可以了。
第一步
首先,引用stdio.h、winsock2.h、windows.h(可有可無,下文講到),注意,這里有一個地方有很多人會出錯,如果你要引用windows.h的話,就得在引用winsock2.h之后才能引用windows.h,否則會出現(xiàn)“未定義標識符”的情況,如下圖↓
這是正確寫法
錯誤寫法
按照錯誤寫法進行調試的話,會出現(xiàn)以下錯誤提示↓
錯誤提示
然后我們再聲明一個變量和兩個函數(shù),變量是用來儲存服務器返回的數(shù)據(jù)的,兩個函數(shù)分別是用來創(chuàng)建套接字(socket)和接收服務器返回數(shù)據(jù)的,這里我們聲明了一個字符型數(shù)組,數(shù)組大小我們用BUFSIZ代替,這里有人就會問了:“為什么用BUFSIZ作為數(shù)組大小呢?”,答案是:“減輕系統(tǒng)負擔”,不理解?沒關系,先把代碼運行起來,然后再慢慢研究。
除了以上步驟,我們還需要寫入以下兩行代碼,加入兩個庫文件,其中User32.lib是可有可無的,加入User32.lib只是為了能夠調用MessageBox()函數(shù)而已。
到這里,我們的第一步完成了!接下來是第二步
第二步
初始化
前期的準備工作做好了,我們現(xiàn)在開始編寫我們要用到的函數(shù)——socket_connect_server(void),從字面的意思上來看,大家都應該明白這個函數(shù)是干嘛的吧?沒錯,它是用來創(chuàng)建套接字并連接SMTP服務器的。
我們要創(chuàng)建一個套接字,初始化完成后,我們要把它記在某個地方,要不然“忘記”了怎么辦?所以我們要聲明一個變量來存放套接字初始化后的數(shù)據(jù)——WSADATA wd,wd就是用來存放這些數(shù)據(jù)的變量。
好了,我們用到的主要變量已經(jīng)聲明完畢,接下來要初始化,我們要向編譯器說明,我們要用到Ws2_32.lib和Winsock2.h中的哪個庫文件(簡單來說就是初始化而已),如圖,代碼可以這么寫↓
創(chuàng)建套接字
開始創(chuàng)建socket,這里我們要用到socket()函數(shù),socket()需要三個參數(shù),但是一般情況下,按照圖中的代碼寫也是可以的,所以,這行代碼各位看官照抄就行了!其實,這三個參數(shù)很容易理解,這里就不“搬書”了。
輸入服務器信息
這里解釋一下inet_addr()函數(shù),它的功能是將一個點分十進制的IP轉換成一個長整數(shù)型數(shù)(u_long類型),說白了,就是數(shù)據(jù)類型轉換,將IP地址的數(shù)據(jù)類型成能夠存到addr這個結構體的數(shù)據(jù)類型。
還有一個htons()函數(shù),它的作用是將括號里面的數(shù)值,轉化成網(wǎng)絡字節(jié)順序(TCP/IP中規(guī)定數(shù)據(jù)表現(xiàn)形式),簡單點講,就是將括號里面的數(shù)值轉化成另一種表現(xiàn)形式。
連接服務器
套接字有了,服務器也有了,接下來要干嘛呢?那就是連接服務器!連接服務器我們要用到connet()函數(shù)而不是bind()函數(shù),這里簡單的記一下“connet()用在客戶端,bind()用在服務器”。
這里跟大家說一下,connet()函數(shù)其中第一個參數(shù)是SOCKADDR類型,而我們這里為什么用SOCKADDR_IN類型呢?請看下圖↓
SOCKADDR_IN強制轉換成SOCKADDR類型
圖中的代碼將smtp郵箱IP地址存放在SOCKADDR_IN的S_addr成員中,然后再將端口號放在sin_port成員中,分開進行,而SOCKADDR就不一樣了,它將IP地址和端口號一起放在sa_data[14]這個成員中,這樣看來SOCKADDR是一種通用的套接字地址,SOCKADDR_IN是internet環(huán)境下套接字的地址形式。說白了,就是“SOCKADDR_IN更適合用于網(wǎng)絡編程”,記住這句話就對了!
第三步
就是我們的recv_show()函數(shù),這個函數(shù)比較簡單,這里就不多說了,照抄!
這里會用到send()函數(shù),它有三個參數(shù),分別是已連接的socket、發(fā)送的字符串、發(fā)送字符串長度、調用執(zhí)行方式(一般為0)。
代碼書寫示例:send(socket_use,"發(fā)送的數(shù)據(jù)",strlen("發(fā)送的數(shù)據(jù)"),0),為什么后面會有?這個跟SMTP協(xié)議有關,與CMD命令行發(fā)送郵件時的“回車”效果一樣。
注意:
接下來就是按照SMTP協(xié)議來發(fā)送數(shù)據(jù)和接收數(shù)據(jù)了
如圖,參照CMD命令通過SMTP協(xié)議發(fā)送郵件的實例,來寫C語言發(fā)送郵件的代碼↓
CMD發(fā)送郵件的過程
舉個例子,我們第一步要發(fā)送“helo 163.com”,那么,我們用C語言發(fā)送是這樣的,send(socket_use,"helo 163.com",strlen("helo 163.com"),0),按照這行代碼,以此類推寫下去,然后再用recv_show()輸出服務器應答的信息。
注意這三行C語言代碼,跟CMD發(fā)郵件過程對比以下↓
這是程序運行之后的結果
以下是全部代碼↓
聯(lián)系客服