這個文章的標題是有點難懂,所以還是要先多解釋兩句。本文的目的,是要在 Linux 內產生一個 virtual comport ,並且 Listen 一個 TCP 連線,當有 TCP 連線連入的時候,就會將資料導入這個 virtual comport,使用者可以透過這個 virtual comport 與連入這進行資料傳輸。由於產生/開啟 device 需要 root 權限,請以 root 權限執行下面提到的命令。
目的
這個用途乍看之下有點疊床架屋,不就直接寫個網路程式就好了嗎!?這樣說也是沒錯,不過一些情況下還是有些用途,但是只會允許一個連入連線,多個可能會造成資料錯亂。
- 不會寫網路程式的人,可以用這個方式直接讀寫 virtual comport ,當做一個 character device,再加上此命令便可以成為接受網路連線的程式。
- 有些程式就是設計用來與 serial port 通訊的,但此時若沒有 serial port,可以藉此命令產生一個 serial port,再利用網路連入,便可使用此程式。
socat 有很多 port forward, 資料傳輸, 資料轉傳的功能,這一篇只是其中小小的一個應用。Windows 上也有一個類似的程式 hub4com + com0com,我會再寫一篇文章介紹。其實我工作上的用途,就是讓 socat 搭配 hub4com,讓 Linux 上的comport程式,和 Windows 上的 comport 程式,可以透過網路來連接起來。
命令與測試程式
1 |
socat -d -d pty,link=/dev/vcom0,rawer tcp-listen:33210,reuseaddr,fork |
以上的命令,會在 /dev/vcom0 產生一個 virtualcom port 裝置,並且Listen local 端的 TCP Port 33210 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main() { int fp; int c; char buf[128]; fp = open("/dev/vcom0", O_RDWR | O_SYNC ); if(fp < 0) { printf("open vcom0 failed\n"); return -1; } while(1) { read(fp, &c, 1); printf("%c", c & 0xFF); sprintf(buf, "receive char 0x%02x at %u epoch time.\n\r", c, time(NULL)); write(fp, buf, strlen(buf)); } } |
當執行完 socat 命令後,就可以寫一支程式,持續的去讀寫 /dev/vcom0 這個檔案,當有 tcp 連線連入時,就可以透過 read / write 與連入的連線做溝通。編譯並執行上面的程式後,
下面我們以一個簡單的 echo 搭配 nc 為例,來與這支程式進行通訊。
上圖右邊是剛剛 C 程式的執行畫面,左圖會 echo 一個文字,並利用 nc 命令連到 local 的 33210 port,並把 “test” 傳過去。當程式收到字後,會把文字印出,並且回覆一些文字,這樣就驗証了我們的測試。
斷開後無法再開啟 COMPORT
這個命令有個現象就是當 comport 被開啟過後,並且也曾經也有網路連線連入過,此後如果關掉comport讀取程式,下次就無法再開啟 (因 /dev/vcom0 已消失),而需重新啟動 socat。但此時 socat 其實仍然再執行,需要手動 kill 再開啟。所以,我最後的實際做法是在 C 程式啟動時,先砍掉 socat ,再啟動一次 socat,這樣就可以避開這個問題了。
結語
socat 功能其實相當強大,資料可以被神奇的轉來轉去,這篇真的只是其中的一小部份。成功的串接 comport 與網路,解決了我工作上的問題,希望對各位讀者也有幫助。其實有支 tcpd 程式也有類似的功能,不過是它是 listen tcp port,並在有連線連入時啟動指定的程式,並與它的 stdin/stdout 連線,這也是以往 inetd 的做法,這樣就可以不需碰觸到網路方面的知識了。當然,相對的,一百個連入連線,就要啟動100個程式來執行,也是個不小的代價。
Latest Comments