前言

前段時間群里討論,想實現某個文件定時上傳到服務器要怎么來實現。我記得之前做過
一個項目:為高通的iot模組編寫FOTA功能:實現模組可以遠程下載升級鏡像包,實現版本升級功能。並當時使用的一個超級強大的工具cURL。心血來潮,決定專門寫一篇文章,送給需要的朋友。
文章分兩部分
- 首先介紹cURL的用法;
- 實現一個定時上傳日志文件的一個簡單的程序。

概念
cURL 是常用的命令行工具,用來請求 Web 服務器。它的名字就是客戶端(client)的 URL 工具的意思。
cURL 的原作者是 Daniel Stenberg (目前是 cURL 的核心開發者),同時也是 IETF HTTPbis 工作組的資深成員。Daniel 在 1998 年創建了 curl 項目,他編寫了最初的 curl 版本,並創建了 libcurl 庫。到目前為止,代碼倉庫包括的 24000 次 commit 有超過一半是 Daniel 本人提交的,他依然是項目的核心開發者。Daniel 表示已將 curl 視為自己的孩子。
作為一款強力工具,支持的協議包括 (DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, TELNET and TFTP),還支持POST、cookies、認證、從指定偏移處下載部分文件等功能,具有用戶代理字符串、限速、文件大小、進度條、cookie支持、用戶認證、斷點續傳等特征。
一、命令的安裝
sudo apt-get install curl
二、cURL命令語法:
curl [options] [URL...]
三、URL格式
URL的格式定義要參考 RFC 1808 。
地址:http://www.w3.org/Addressing/rfc1808.txt
《Relative Uniform Resource Locators 》
URL由三部分組成:資源類型、存放資源的主機域名、資源文件名。
也可認為由4部分組成:協議、主機、端口、路徑
URL的一般語法格式為:
protocol :// hostname[:port] / path / [;parameters][?query]#fragment
(帶方括號[]的為可選項)。
protocol(協議)
指定使用的傳輸協議,下表列出 protocol 屬性的有效方案名稱。 最常用的是HTTP協議,它也是WWW中應用最廣的協議。
- file 資源是本地計算機上的文件。格式file:///,注意后邊應是三個斜杠。
- ftp 通過 FTP訪問資源。格式 FTP://
- gopher 通過 Gopher 協議訪問該資源。
- http 通過 HTTP 訪問該資源。 格式 HTTP://
- https 通過安全的 HTTPS 訪問該資源。 格式 HTTPS://
- mailto 資源為電子郵件地址,通過 SMTP 訪問。 格式 mailto:
- MMS 通過 支持MMS(流媒體)協議的播放該資源。(代表軟件:Windows Media Player)格式 MMS://
- ed2k 通過 支持ed2k(專用下載鏈接)協議的P2P軟件訪問該資源。(代表軟件:電驢) 格式 ed2k://
- Flashget 通過 支持Flashget:(專用下載鏈接)協議的P2P軟件訪問該資源。(代表軟件:快車) 格式 Flashget://
- thunder 通過 支持thunder(專用下載鏈接)協議的P2P軟件訪問該資源。(代表軟件:迅雷) 格式 thunder://
- news 通過 NNTP 訪問該資源。
hostname(主機名)
是指存放資源的服務器的域名系統(DNS) 主機名或 IP 地址。有時,在主機名前也可以包含連接到服務器所需的用戶名和密碼(格式:username:password@hostname)。
port(端口號)
整數,可選,省略時使用方案的默認端口,各種傳輸協議都有默認的端口號,如http的默認端口為80。如果輸入時省略,則使用默認端口號。有時候出於安全或其他考慮,可以在服務器上對端口進行重定義,即采用非標准端口號,此時,URL中就不能省略端口號這一項。
path(路徑)
由零或多個“/”符號隔開的字符串,一般用來表示主機上的一個目錄或文件地址。
parameters(參數)
這是用於指定特殊參數的可選項。
query(查詢)
可選,用於給動態網頁(如使用CGI、ISAPI、PHP/JSP/ASP/ASP.NET等技術制作的網頁)傳遞參數,可有多個參數,用“&”符號隔開,每個參數的名和值用“=”符號隔開。
fragment(信息片斷)
字符串,用於指定網絡資源中的片斷。例如一個網頁中有多個名詞解釋,可使用fragment直接定位到某一名詞解釋。
四、curl命令參數詳解:
由於linux curl功能十分強大,所以命令參數十分多,下表只篩選出來部分常用的參數,更多參數請運行“man curl”命令查看。
| 參數 | 功能 |
|---|---|
| -a/--append | 上傳文件時,附加到目標文件 |
| -A/--user-agent
|
設置用戶代理發送給服務器 |
| -anyauth | 可以使用“任何”身份驗證方法 |
| -b/--cookie <name=string/file> | cookie字符串或文件讀取位置 |
| --basic | 使用HTTP基本驗證 |
| -B/--use-ascii | 使用ASCII /文本傳輸 |
| -c/--cookie-jar
|
操作結束后把cookie寫入到這個文件中 |
| -C/--continue-at
|
斷點續轉 |
| -d/--data | HTTP POST方式傳送數據 |
| --data-ascii | 以ascii的方式post數據 |
| --data-binary | 以二進制的方式post數據 |
| --negotiate | 使用HTTP身份驗證 |
| --digest | 使用數字身份驗證 |
| --disable-eprt | 禁止使用EPRT或LPRT |
| --disable-epsv | 禁止使用EPSV |
| -D/--dump-header
|
把header信息寫入到該文件中 |
| --egd-file
|
為隨機數據(SSL)設置EGD socket路徑 |
| --tcp-nodelay | 使用TCP_NODELAY選項 |
| -e/--referer | 來源網址 |
| -E/--cert <cert[:passwd]> | 客戶端證書文件和密碼 (SSL) |
| --cert-type
|
證書文件類型 (DER/PEM/ENG) (SSL) |
| --key
|
私鑰文件名 (SSL) |
| --key-type
|
私鑰文件類型 (DER/PEM/ENG) (SSL) |
| --pass
|
私鑰密碼 (SSL) |
| --engine
|
加密引擎使用 (SSL). "--engine list" for list |
| --cacert
|
CA證書 (SSL) |
| --capath
|
CA目錄 (made using c_rehash) to verify peer against (SSL) |
| --ciphers
|
SSL密碼 |
| --compressed | 要求返回是壓縮的形勢 (using deflate or gzip) |
| --connect-timeout
|
設置最大請求時間 |
| --create-dirs | 建立本地目錄的目錄層次結構 |
| --crlf | 上傳是把LF轉變成CRLF |
| -f/--fail | 連接失敗時不顯示http錯誤 |
| --ftp-create-dirs | 如果遠程目錄不存在,創建遠程目錄 |
| --ftp-method [multicwd/nocwd/singlecwd] | 控制CWD的使用 |
| --ftp-pasv | 使用 PASV/EPSV 代替端口 |
| --ftp-skip-pasv-ip | 使用PASV的時候,忽略該IP地址 |
| --ftp-ssl | 嘗試用 SSL/TLS 來進行ftp數據傳輸 |
| --ftp-ssl-reqd | 要求用 SSL/TLS 來進行ftp數據傳輸 |
| -F/--form <name=content> | 模擬http表單提交數據 |
| --form-string <name=string> | 模擬http表單提交數據 |
| -g/--globoff | 禁用網址序列和范圍使用{}和[] |
| -G/--get | 以get的方式來發送數據 |
| -H/--header
|
自定義頭信息傳遞給服務器 |
| --ignore-content-length | 忽略的HTTP頭信息的長度 |
| -i/--include | 輸出時包括protocol頭信息 |
| -I/--head | 只顯示請求頭信息 |
| -j/--junk-session-cookies | 讀取文件進忽略session cookie |
| --interface
|
使用指定網絡接口/地址 |
| --krb4
|
使用指定安全級別的krb4 |
| -k/--insecure | 允許不使用證書到SSL站點 |
| -K/--config | 指定的配置文件讀取 |
| -l/--list-only | 列出ftp目錄下的文件名稱 |
| --limit-rate
|
設置傳輸速度 |
| --local-port
|
強制使用本地端口號 |
| -m/--max-time
|
設置最大傳輸時間 |
| --max-redirs
|
設置最大讀取的目錄數 |
| --max-filesize
|
設置最大下載的文件總量 |
| -M/--manual | 顯示全手動 |
| -n/--netrc | 從netrc文件中讀取用戶名和密碼 |
| --netrc-optional | 使用 .netrc 或者 URL來覆蓋-n |
| --ntlm | 使用 HTTP NTLM 身份驗證 |
| -N/--no-buffer | 禁用緩沖輸出 |
| -o/--output | 把輸出寫到該文件中 |
| -O/--remote-name | 把輸出寫到該文件中,保留遠程文件的文件名 |
| -p/--proxytunnel | 使用HTTP代理 |
| --proxy-anyauth | 選擇任一代理身份驗證方法 |
| --proxy-basic | 在代理上使用基本身份驗證 |
| --proxy-digest | 在代理上使用數字身份驗證 |
| --proxy-ntlm | 在代理上使用ntlm身份驗證 |
| -P/--ftp-port | 使用端口地址,而不是使用PASV |
| -q | 作為第一個參數,關閉 .curlrc |
| -Q/--quote
|
文件傳輸前,發送命令到服務器 |
| -r/--range
|
檢索來自HTTP/1.1或FTP服務器字節范圍 |
| --range-file | 讀取(SSL)的隨機文件 |
| -R/--remote-time | 在本地生成文件時,保留遠程文件時間 |
| --retry
|
傳輸出現問題時,重試的次數 |
| --retry-delay
|
傳輸出現問題時,設置重試間隔時間 |
| --retry-max-time
|
傳輸出現問題時,設置最大重試時間 |
| -s/--silent | 靜默模式。不輸出任何東西 |
| -S/--show-error | 顯示錯誤 |
| --socks4 <host[:port]> | 用socks4代理給定主機和端口 |
| --socks5 <host[:port]> | 用socks5代理給定主機和端口 |
| --stderr
|
|
| -t/--telnet-option <OPT=val> | Telnet選項設置 |
| --trace
|
對指定文件進行debug |
| --trace-ascii
|
Like --跟蹤但沒有hex輸出 |
| --trace-time | 跟蹤/詳細輸出時,添加時間戳 |
| -T/--upload-file
|
上傳文件 |
| --url
|
Spet URL to work with |
| -u/--user <user[:password]> | 設置服務器的用戶和密碼 |
| -U/--proxy-user <user[:password]> | 設置代理用戶名和密碼 |
| -w/--write-out [format] | 什么輸出完成后 |
| -x/--proxy <host[:port]> | 在給定的端口上使用HTTP代理 |
| -X/--request |
指定什么命令 |
| -y/--speed-time | 放棄限速所要的時間,默認為30 |
| -Y/--speed-limit | 停止傳輸速度的限制,速度時間 |
五、Linux curl命令退出碼:
下面是linux curl命令的錯誤代碼和她們的相應的錯誤消息,命令執行錯誤的時候可以通過錯誤碼來查看出錯原因,方便開發調試。
| 退 出 碼 | 錯誤描述 |
|---|---|
| 1 | Unsupported protocol. This build of curl has no support for this protocol. |
| 2 | Failed to initialize. |
| 3 | URL malformed. The syntax was not correct. |
| 5 | Couldn't resolve proxy. The given proxy host could not be resolved. |
| 6 | Couldn't resolve host. The given remote host was not resolved. |
| 7 | Failed to connect to host. |
| 8 | FTP weird server reply. The server sent data curl couldn't parse. |
| 9 | FTP access denied. The server denied login or denied access to the particular resource or directory you wanted to reach. Most often you tried to change to a directory that doesn't exist on the server. |
| 11 | FTP weird PASS reply. Curl couldn't parse the reply sent to the PASS request. |
| 13 | FTP weird PASV reply, Curl couldn't parse the reply sent to the PASV request. |
| 14 | FTP weird 227 format. Curl couldn't parse the 227-line the server sent. |
| 15 | FTP can't get host. Couldn't resolve the host IP we got in the 227-line. |
| 17 | FTP couldn't set binary. Couldn't change transfer method to binary. |
| 18 | Partial file. Only a part of the file was transferred. |
| 19 | FTP couldn't download/access the given file, the RETR (or similar) command failed. |
| 21 | FTP quote error. A quote command returned error from the server. |
| 22 | HTTP page not retrieved. The requested url was not found or returned another error with the HTTP error code being 400 or above. This return code only appears if -f/--fail is used. |
| 23 | Write error. Curl couldn't write data to a local filesystem or similar. |
| 25 | FTP couldn't STOR file. The server denied the STOR operation, used for FTP uploading. |
| 26 | Read error. Various reading problems. |
| 27 | Out of memory. A memory allocation request failed. |
| 28 | Operation timeout. The specified time-out period was reached according to the conditions. |
| 30 | FTP PORT failed. The PORT command failed. Not all FTP servers support the PORT command, try doing a transfer using PASV instead! |
| 31 | FTP couldn't use REST. The REST command failed. This command is used for resumed FTP transfers. |
| 33 | HTTP range error. The range "command" didn't work. |
| 34 | HTTP post error. Internal post-request generation error. |
| 35 | SSL connect error. The SSL handshaking failed. |
| 36 | FTP bad download resume. Couldn't continue an earlier aborted download. |
| 37 | FILE couldn't read file. Failed to open the file. Permissions? |
| 38 | LDAP cannot bind. LDAP bind operation failed. |
| 39 | LDAP search failed. |
| 41 | Function not found. A required LDAP function was not found. |
| 42 | Aborted by callback. An application told curl to abort the operation. |
| 43 | Internal error. A function was called with a bad parameter. |
| 45 | Interface error. A specified outgoing interface could not be used. |
| 47 | Too many redirects. When following redirects, curl hit the maximum amount. |
| 48 | Unknown TELNET option specified. |
| 49 | Malformed telnet option. |
| 51 | The peer's SSL certificate or SSH MD5 fingerprint was not ok. |
| 52 | The server didn't reply anything, which here is considered an error. |
| 53 | SSL crypto engine not found. |
| 54 | Cannot set SSL crypto engine as default. |
| 55 | Failed sending network data. |
| 56 | Failure in receiving network data. |
| 58 | Problem with the local certificate. |
| 59 | Couldn't use specified SSL cipher. |
| 60 | Peer certificate cannot be authenticated with known CA certificates. |
| 61 | Unrecognized transfer encoding. |
| 62 | Invalid LDAP URL. |
| 63 | Maximum file size exceeded. |
| 64 | Requested FTP SSL level failed. |
| 65 | Sending the data requires a rewind that failed. |
| 66 | Failed to initialize SSL Engine. |
| 67 | The user name, password, or similar was not accepted and curl failed to log in. |
| 68 | File not found on TFTP server. |
| 69 | Permission problem on TFTP server. |
| 70 | Out of disk space on TFTP server. |
| 71 | Illegal TFTP operation. |
| 72 | Unknown TFTP transfer ID. |
| 73 | File already exists (TFTP). |
| 74 | No such user (TFTP). |
| 75 | Character conversion failed. |
| 76 | Character conversion functions required. |
| 77 | Problem with reading the SSL CA cert (path? access rights?). |
| 78 | The resource referenced in the URL does not exist. |
| 79 | An unspecified error occurred during the SSH session. |
| 80 | Failed to shut down the SSL connection. |
| 82 | Could not load CRL file, missing or wrong format (added in 7.19.0). |
| 83 | Issuer check failed (added in 7.19.0). |
| XX | More error codes will appear here in future releases. The existing ones are meant to never change. |
六、用法演示:
為節省篇幅,部分操作不再貼上執行結果。
1、查看網頁源碼
直接在curl命令后加上網址,就可以看到網頁源碼。我們以網址www.sina.com為例(選擇該網址,主要因為它的網頁代碼較短):
root@ubuntu:/home/peng# curl www.sohu.com
<html>
<head><title>307 Temporary Redirect</title></head>
<body bgcolor="white">
<center><h1>307 Temporary Redirect</h1></center>
<hr><center>nginx</center>
</body>
</html>
執行結果顯示 307 Temporary Redirect,說明該網址需要重定向。
如果要把這個網頁保存下來,可以使用-o參數,這就相當於使用wget命令了。
curl -o [文件名] www.sohu.com
2、自動跳轉
有的網址是自動跳轉的。使用-L參數,curl就會跳轉到新的網址。
curl -L www.sohu.com
鍵入上面的命令,結果就自動跳轉為www.sohu.com.cn。
3、顯示頭信息
-i參數可以顯示http response的頭信息,連同網頁代碼一起。
root@ubuntu:/home/peng/driver/test# curl -i www.sohu.com
HTTP/1.1 307 Temporary Redirect
Content-Type: text/html
Content-Length: 180
Connection: keep-alive
Server: nginx
Date: Tue, 25 Aug 2020 10:10:54 GMT
Location: https://www.sohu.com/
FSS-Cache: from 9790436.18244590.10468709
FSS-Proxy: Powered by 2384755.3433341.3062915
<html>
<head><title>307 Temporary Redirect</title></head>
<body bgcolor="white">
<center><h1>307 Temporary Redirect</h1></center>
<hr><center>nginx</center>
</body>
</html>
-I參數則是只顯示http response的頭信息。
4、顯示通信過程
-v參數可以顯示一次http通信的整個過程,包括端口連接和http request頭信息。
root@ubuntu:/home/peng/driver/test# curl -v www.sohu.com
* About to connect() to www.sohu.com port 80 (#0)
* Trying 240e:83:201:3700::5... connected
> GET / HTTP/1.1
> User-Agent: curl/7.22.0 (i686-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: www.sohu.com
> Accept: */*
>
< HTTP/1.1 307 Temporary Redirect
< Content-Type: text/html
< Content-Length: 180
< Connection: keep-alive
< Server: nginx
< Date: Tue, 25 Aug 2020 10:11:49 GMT
< Location: https://www.sohu.com/
< FSS-Cache: from 9855973.18375663.10534247
< FSS-Proxy: Powered by 2450292.3564414.3128453
<
<html>
<head><title>307 Temporary Redirect</title></head>
<body bgcolor="white">
<center><h1>307 Temporary Redirect</h1></center>
<hr><center>nginx</center>
</body>
</html>
* Connection #0 to host www.sohu.com left intact
* Closing connection #0
如果你覺得上面的信息還不夠,那么下面的命令可以查看更詳細的通信過程。
curl --trace output.txt www.sohu.com
或者
curl --trace-ascii output.txt www.sohu.com
運行后,請打開output.txt文件查看。
5、發送表單信息
發送表單信息有GET和POST兩種方法。GET方法相對簡單,只要把數據附在網址后面就行。
curl example.com/form.cgi?data=xxx
POST方法必須把數據和網址分開,curl就要用到--data參數。
curl -X POST --data "data=xxx" example.com/form.cgi
如果你的數據沒有經過表單編碼,還可以讓curl為你編碼,參數是--data-urlencode。
curl -X POST--data-urlencode "date=April 1" example.com/form.cgi
6、HTTP動詞
curl默認的HTTP動詞是GET,使用-X參數可以支持其他動詞。
curl -X POST www.example.com
curl -X DELETE www.example.com
7、文件上傳
假定文件上傳的表單是下面這樣:
<form method="POST" enctype='multipart/form-data' action="upload.cgi">
<input type=file name=upload>
<input type=submit name=press value="OK">
</form>
你可以用curl這樣上傳文件:
curl --form upload=@localfilename --form press=OK [URL]
8、Referer字段
有時你需要在http request頭信息中,提供一個referer字段,表示你是從哪里跳轉過來的。
curl --referer http://www.example.com http://www.example.com
9、User Agent字段
這個字段是用來表示客戶端的設備信息。服務器有時會根據這個字段,針對不同設備,返回不同格式的網頁,比如手機版和桌面版。
iPhone4的User Agent是
Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7
curl可以這樣模擬:
curl --user-agent "[User Agent]" [URL]
10、cookie
使用--cookie參數,可以讓curl發送cookie。
curl --cookie "name=xxx" www.example.com
至於具體的cookie的值,可以從http response頭信息的Set-Cookie字段中得到。
-c cookie-file可以保存服務器返回的cookie到文件,-b cookie-file可以使用這個文件作為cookie信息,進行后續的請求。
curl -c cookies http://example.com
curl -b cookies http://example.com
11、增加頭信息
有時需要在http request之中,自行增加一個頭信息。--header參數就可以起到這個作用。
$ curl --header "Content-Type:application/json" http://example.com
12、認證
使用curl選項 -u 可以完成HTTP或者FTP的認證,可以指定密碼,也可以不指定密碼在后續操作中輸入密碼:
curl -u user:pwd http://man.linuxde.net
curl -u user http://man.linuxde.net
13、FTP
1)、列出ftp服務器上的目錄列表
curl ftp://www.xxx.com/ --user name:passwd
curl ftp://www.xxx.com/ –u name:passwd #簡潔寫法
curl ftp://name:passwd@www.xxx.com #簡潔寫法2
例如:在IP地址192.168.43.117上搭建FTP服務器,並設置用戶名為user,密碼為123456
現在我們要顯示服務器上根目錄下的所有文件信息,命令如下:
curl -u user:123456 ftp://192.168.43.117
執行結果如下:

簡潔寫法:
curl ftp://user:123456@192.168.43.117
執行結果如下:

2)、只列出目錄,不顯示進度條
curl ftp://www.xxx.com –u name:passwd -s
3)、下載一個文件:
格式
curl ftp://www.xxx.com/size.zip –u name:passwd -o size.zip
示例如下:
從服務器的根目錄下下載文件test.c,保存到本地,本地文件名也為test.c。
【注意】如果沒有-o選項,程序會吧數據流定向到stdout,即直接把文件內容顯示到終端上。
curl ftp://user:123456@192.168.43.117/test.c -o test.c
執行結果如下:

簡潔模式
curl -u user:123456 ftp://192.168.43.117/list.h -o list.h
執行結果如下:

4)、上載一個文件:
curl –u name:passwd -T size.mp3 ftp://www.xxx.com/mp3/
舉例如下:
curl -u user:123456 ftp://192.168.43.117/ -T list.h

可以看到文件並沒有上傳成功,返回錯誤碼是25,參考第五章
25 FTP couldn't STOR file. The server denied the STOR operation, used for FTP uploading.
可知,是因為服務器沒有賦予存儲的權限,所以設置服務器的write權限即可。

5)、從服務器上刪除文件(使用curl傳遞ftp協議的DELE命令):
curl –u name:passwd ftp://www.xxx.com/ -X 'DELE mp3/size.mp3'
6)、另外curl不支持遞歸下載,不過可以用數組方式下載文件,比如我們要下載1-10.gif連續命名的文件:**
curl –u name:passwd ftp://www.xxx.com/img/[1-10].gif –O #O字母大寫
7)、要連續下載多個文件:
curl –u name:passwd ftp://www.xxx.com/img/[one,two,three].jpg –O #O字母大寫
六、實現日志文件定時上傳
功能
- 程序運行時要記錄當前日志文件的最后修改時間;
- 每個10秒鍾就檢查下log文件是否被修改,如果沒有被修改就休眠10秒鍾;
- 如果log文件被修改了,就將當前的日志文件拷貝成備份文件,備份文件名字加上當前時間;
- 通過curl發送給ftp服務器;
- 刪除備份文件,重復步驟2。
程序流程圖如下:

函數功能介紹
init()
首先記錄當前log文件時間,並記錄到全局變量last_mtime中。
check_file_change()
讀取文件最后修改時間,並和last_mtime進行比較,如果相同就返回0,不同就返回1.
file_name_add_time()
將當前的日志文件拷貝成備份文件,備份文件名字加上當前時間。
stat()
得到對應文件的屬性信息,存放到struct stat結構體變量中。
system()
執行參數中字符串對應的命令
代碼如下:
/* Copyright (C) 公眾號: yikoulinux */
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
typedef struct stat ST;
unsigned long last_mtime;
/*用戶名密碼暫時寫死,實際應該保存在配置文件*/
char name[32]="user";
char pass[32] ="123456";
char ip[32] ="192.168.43.117";
char filename[32]="t.log";
char dstfile[256] ={0};
int init(void)
{
//准備結構體
ST status;
//調用stat函數
int res = stat(filename,&status);
if(-1 == res)
{
perror("error:open file fail\n");
return 0;
}
last_mtime = status.st_mtime;
printf("init time:%s \n",ctime(&last_mtime));
return 1;
}
int check_file_change(void)
{
//准備結構體
ST status;
//調用stat函數
int res = stat(filename,&status);
if(-1 == res)
{
perror("error:open file fail\n");
return 0;
}
// printf("old:%s new:%s",ctime(&last_mtime),ctime(&status.st_mtime));
if(last_mtime == status.st_mtime)
{
printf("file not change\n");
return 0;
}else{
printf("file updated\n");
last_mtime = status.st_mtime;
return 1;
}
}
void file_name_add_time(void)
{
ST status;
time_t t;
struct tm *tblock;
char cmd[1024]={0};
t = time(NULL);
tblock = localtime(&t);
sprintf(dstfile,"t-%d-%d-%d-%d-%d-%d.log",
tblock->tm_year+1900,
tblock->tm_mon,
tblock->tm_mday,
tblock->tm_hour,
tblock->tm_min,
tblock->tm_sec);
sprintf(cmd,"cp %s %s",filename,dstfile);
// printf("cdm=%s\n",cmd);
system(cmd);
}
int main(void)
{
char cmd[1024]={0};
init();
while(1)
{
if(check_file_change() == 1)
{
file_name_add_time();
sprintf(cmd,"curl -u %s:%s ftp://%s/ -T %s",name,pass,ip,dstfile);
// printf("cdm=%s\n",cmd);
system(cmd);
unlink(dstfile);
}
sleep(10);
}
}
運行截圖:
第一步:

因為log文件沒有被修改過,所以程序不會上傳。
第二步:
手動輸入字符串 yikoulinux 到日志文件 t.log中。
第三步:
因為文件發生了改變,所以打印“file updated”,同時可以看到curl上傳文件的log信息。
以下是FTP服務器的根目錄,可以看到,上傳的日志文件:t-2020-7-26-1-19-45.log。

【補充】
- 配置信息,直接在代碼中寫死,通常應該從配置文件中讀取,為方便讀者閱讀,本代碼沒有增加該功能;
- FTP服務器搭建,本文沒有說明,相關文件比較多,大家可以自行搜索,一口君用的是File zilla;

- 通常這種需要長時間運行的程序,需要設置成守護進程,本文沒有添加相應功能,讀者可以自行搜索。如果強烈要求可以單開一篇詳細介紹。
- 代碼中time的管理函數,請讀者自行搜索相關文章。
- curl也提供了相關的函數庫curl.lib,如果要實現更靈活的功能可以使用對應的api。
- 之所以先把文件拷貝成備份文件,主要是考慮其他模塊隨時可能修改日志文件,起到一定保護作用。
想和博主交流,請關注公眾號「一口Linux」
