簡體   English   中英

Linux C:“交互式會話”,具有單獨的讀寫命名管道?

[英]Linux C: “Interactive session” with separate read and write named pipes?

", link ; 我正在嘗試使用“ ”, 鏈接 ; 特別是fd_server.c (包含在下面以供參考)

這是我的信息和編譯行:

:~$ cat /etc/issue
Ubuntu 10.04 LTS \n \l
:~$ gcc --version
gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3
:~$ gcc fd_server.c -o fd_server

fd_server.c創建了兩個命名管道,一個用於讀取,一個用於寫入。 可以做的是:在一個終端中,運行服務器並讀取(通過cat )其寫入管道:

:~$ ./fd_server & 2>/dev/null 
[1] 11354
:~$ cat /tmp/np2

在另一個中,寫入(使用echo)到服務器的讀管道:

:~$ echo "heeellloooo" > /tmp/np1

回到第一個終端,可以看到:

:~$ cat /tmp/np2 
HEEELLLOOOO
0[1]+  Exit 13                 ./fd_server 2> /dev/null

我想做的是做一個“互動”(或“shell”式)會話; 也就是說,服務器像往常一樣運行,但我不想運行catecho ,而是想使用類似於屏幕的東西。 我的意思是,屏幕可以被稱為screen /dev/ttyS0 38400 ,然后它會進行一種交互式會話,其中在終端中鍵入的內容被傳遞到/dev/ttyS0 ,並且其響應被寫入到終點站。 現在,當然,我不能使用screen ,因為在我的情況下程序有兩個單獨的節點,據我所知, screen只能參考一個。

如何在這種情況下實現這種“交互式”會話(使用兩個獨立的讀/寫管道)?

代碼如下:

#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//#include <fullduplex.h> /* For name of the named-pipe */
#define NP1     "/tmp/np1"
#define NP2     "/tmp/np2"
#define MAX_BUF_SIZE    255
#include <stdlib.h> //exit
#include <string.h> //strlen

int main(int argc, char *argv[])
{
    int rdfd, wrfd, ret_val, count, numread;
    char buf[MAX_BUF_SIZE];

    /* Create the first named - pipe */
    ret_val = mkfifo(NP1, 0666);

    if ((ret_val == -1) && (errno != EEXIST)) {
        perror("Error creating the named pipe");
        exit (1);
    }

    ret_val = mkfifo(NP2, 0666);

    if ((ret_val == -1) && (errno != EEXIST)) {
        perror("Error creating the named pipe");
        exit (1);
    }

    /* Open the first named pipe for reading */
    rdfd = open(NP1, O_RDONLY);

    /* Open the second named pipe for writing */
    wrfd = open(NP2, O_WRONLY);

    /* Read from the first pipe */
    numread = read(rdfd, buf, MAX_BUF_SIZE);

    buf[numread] = '0';

    fprintf(stderr, "Full Duplex Server : Read From the pipe : %sn", buf);

    /* Convert to the string to upper case */
    count = 0;
    while (count < numread) {
        buf[count] = toupper(buf[count]);
        count++;
    }

    /*
     * Write the converted string back to the second
     * pipe
     */
    write(wrfd, buf, strlen(buf));
}

編輯:

") for the above program is below: 是的,只是為了澄清 - 似乎我找到了一個討論非常類似的文檔 ,它是 - 對那里的腳本進行修改(“ “)以上程序如下:

# stty raw # 
( ./fd_server 2>/dev/null; )&
bgPidS=$!
( cat < /tmp/np2 ; )&
bgPid=$!
# Read commands from user, send them to device
echo $(kill -0 $bgPidS 2>/dev/null ; echo $?)
while [ "$(kill -0 $bgPidS 2>/dev/null ; echo $?)" -eq "0" ] && read cmd; do
   # redirect debug msgs to stderr, as here we're redirected to /tmp/np1
   echo "$? - $bgPidS - $bgPid" >&2
   echo "$cmd"
   echo -e "\nproc: $(kill -0 $bgPidS 2>/dev/null ; echo $?)" >&2
done >/tmp/np1
echo OUT
# Terminate background read process - if they still exist
if [ "$(kill -0 $bgPid 2>/dev/null ; echo $?)" -eq "0" ] ;
then
    kill $bgPid
fi
if [ "$(kill -0 $bgPidS 2>/dev/null ; echo $?)" -eq "0" ] ;
then
    kill $bgPidS
fi
# stty cooked

因此,將腳本保存為starter.sh並調用它,會產生以下會話:

$ ./starter.sh 
0
i'm typing here and pressing [enter] at end
0 - 13496 - 13497
I'M TYPING HERE AND PRESSING [ENTER] AT END
0~�.N=�(�~� �����}����@������~� [garble]
proc: 0
OUT

這就是我所謂的“交互式會話”(忽略調試語句) - 服務器等待我輸入命令; 它在收到命令后給出它的輸出(並且在這種情況下它在第一個命令之后退出,啟動腳本也是如此)。 除此之外,我希望沒有緩沖輸入,但是逐個字符發送(意味着上面的會話應該在第一次按鍵后退出,並打印出一個字母 - 這是我所期望的stty raw會有所幫助,但是它不會:它只會殺死對EnterCtrl - C :)的反應)

如果已經存在一個現有的命令(類似於串行設備的screen ,我猜),我會徘徊,它會接受兩個這樣的命名管道作為參數,並通過它們建立一個“終端”或“shell”之類的會話; 或者我是否必須使用上面的腳本和/或編程自己的“客戶端”,它將充當終端..

如果你只是希望能夠接收多行,而不是在一行之后退出,這很簡單。 你只需要在你的讀/寫代碼周圍放置一個循環,就像這樣(快速和臟):

while( 1 ) {
    numread = read(rdfd, buf, MAX_BUF_SIZE);

    fprintf(stderr, "Full Duplex Server : Read From the pipe : %sn", buf);

    /* Convert to the string to upper case */
    count = 0;
    while (count < numread) {
        buf[count] = toupper(buf[count]);
        count++;
    }

    /*
     * Write the converted string back to the second
     * pipe
     */
    write(wrfd, buf, strlen(buf));
}

當然,現在你有一個永遠不會退出的應用程序,並且只要它獲得EOF等就會開始無所事事。所以,你可以重新組織它以檢查錯誤:

numread = read(rdfd, buf, MAX_BUF_SIZE);
while( numread > 0) {
    /* ... etc ... */
    numread = read(rdfd,buf, MAX_BUF_SIZE);
}
if( numread == 0 )  {
    /* ... handle eof ... */
}
if( numread < 0 ) {
    /* ... handle io error ... */
} 

從手冊頁中,對於EOF,讀取返回0,對於錯誤,讀取返回-1(您已閱讀手冊頁,對吧? http://linux.die.net/man/2/read )。 所以這樣做是繼續從讀取管道抓取字節,直到它達到EOF或一些錯誤,在這種情況下你(可能)打印一條消息並退出。 也就是說,當你得到一個EOF時你可能只是重新打開,這樣你就可以得到更多的輸入。

一旦您將程序修改為連續讀取,交互式輸入多行就很簡單。 只需執行:

cat - > /tmp/np1

' - '顯式告訴cat從stdin讀取(這是默認值,所以你實際上並不需要破折號)。 因此,cat會將您輸入的所有內容傳遞給管道程序。 您可以使用Ctrl + D插入EOF,這將導致cat停止讀取標准輸入。 您的管道程序會發生什么取決於您在讀取循環中如何處理EOF。

現在,如果你想要另一個程序執行所有io,沒有cat,(所以你最終得到一個stdio echo程序),偽代碼看起來會像這樣:

const int stdin_fd = 0;  // known unix constant!
int readpipe_fd = open the read pipe, as before 
int writepipe_fd =  open the write pipe, as before 
read stdin into buffer
while( stdin is reading correctly ) {
     write data from stdin to read pipe
         check write is successful
     read write pipe into buffer
         check read is successful
     write buffer to stdout (fprintf is fine)
     read stdin into buffer.
}

如果您願意,可以使用read系統調用來讀取stdin,但您也可以使用stdio。 讀取,寫入和打開管道都應該與服務器程序完全相同,除了讀取/寫入都是相反的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM