linux管道與通訊端的調試工具
來源:互聯網
上載者:User
1)管道的調試/proc/pid/fd目錄下列出進程的管道和管道的索引號.我們用下面的程式來看管道在/proc/pid/fd目錄下的表現,如下:#include<unistd.h>#include<sys/types.h>#include<stdio.h>#include<stdlib.h>#include<string.h>int main(){ pid_t pid; int fd[2],nbytes; char string[]="data from child process"; char buf[100]; if(pipe(fd)<0) { perror("pipe"); exit(1); } if((pid=fork())==-1) { perror("fork"); exit(1); } if(pid==0) { close(fd[0]); printf("childpid =%2d\n",getpid()); write(fd[1],string,sizeof(string)); close(fd[1]); exit(0); } else { printf("parentpid =%2d\n",getpid()); sleep(30); close(fd[1]); nbytes=read(fd[0],buf,sizeof(buf)); printf("Received string:%s\n",buf); close(fd[0]); } return 0;}編譯:gcc pipe.c -o pipe 運行:./pipe childpid =27695parentpid = 27694程式會在父進程執行時調用sleep(30),此時子進程已經完成對管道的寫入,並關閉了子進程的管道(讀/寫兩端).父進程在sleep(30)秒後,從管道讀取資訊並輸出.我們在父進程睡眠的時候,根據它的parentpid輸出,來查看它的檔案描述符,如下:ls -l /proc/27694/fdtotal 0lrwx------ 1 root root 64 Mar 18 13:06 0 -> /dev/pts/0lrwx------ 1 root root 64 Mar 18 13:06 1 -> /dev/pts/0lrwx------ 1 root root 64 Mar 18 13:06 2 -> /dev/pts/0lr-x------ 1 root root 64 Mar 18 13:06 3 -> pipe:[42753]l-wx------ 1 root root 64 Mar 18 13:06 4 -> pipe:[42753]這裡的3 -> pipe:[42753],表示管道的讀取端,4 -> pipe:[42753]表示管道的寫入端.相同我們也可以根據管道的索引號得到它的進程,如下:lsof |head -1 && lsof | grep 43046COMMAND PID USER FD TYPE DEVICE SIZE NODE NAMEpipe 27780 root 3r FIFO 0,6 43046 pipepipe 27780 root 4w FIFO 0,6 43046 pipe2)通訊端的調試調試通訊端時兩個最有用的工具是netstat和lsof#include <stdio.h>#include <string.h>#include <signal.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/un.h>#define ASSERTNOERR(x, msg) do{\ if ((x) == -1){perror(msg); exit(1);}}while(0)#define SOCKNAME "localsock"int main (int argc, char *argv[]){ int s = socket(PF_LOCAL, SOCK_STREAM, 0); struct sockaddr_un sa = { .sun_family = AF_LOCAL, .sun_path = SOCKNAME }; int r = bind(s, (struct sockaddr *) &sa, sizeof(sa)); ASSERTNOERR(r, "bind"); r = listen(s, 0); ASSERTNOERR(r, "listen"); struct sockaddr_un asa; size_t addrlen = sizeof(asa); int fd = accept(s, (struct sockaddr *) &asa, &addrlen); ASSERTNOERR(fd, "accept"); while(1){ char buf[32]; fd_set fds; FD_ZERO(&fds); FD_SET(fd, &fds); int r = select (fd+1, &fds, NULL, NULL, NULL); ASSERTNOERR(r, "select"); int n = read(fd, buf, sizeof(buf)); printf("server read %d bytes\n", n); if(n == 0) break; } unlink(SOCKNAME); return 0;}編譯:gcc unix-socket.c -o unix-socket用netstat來查看處於監聽狀態的UNIX socket通訊端,如下:netstat -nlxpActive UNIX domain sockets (only servers)Proto RefCnt Flags Type State I-Node PID/Program name Pathunix 2 [ ACC ] STREAM LISTENING 4899 1967/sdpd /var/run/sdpunix 2 [ ACC ] STREAM LISTENING 5534 2260/xfs /tmp/.font-unix/fs7100unix 2 [ ACC ] STREAM LISTENING 6586 2468/1 /tmp/ssh-yWORhw2468/agent.2468unix 2 [ ACC ] STREAM LISTENING 8331 2879/unix-socket /tmp/localsockunix 2 [ ACC ] STREAM LISTENING 4988 2030/pcscd /var/run/pcscd.communix 2 [ ACC ] STREAM LISTENING 5151 2103/acpid /var/run/acpid.socketunix 2 [ ACC ] STREAM LISTENING 5412 2206/gpm /dev/gpmctlunix 2 [ ACC ] STREAM LISTENING 5631 2311/avahi-daemon: /var/run/avahi-daemon/socketunix 2 [ ACC ] STREAM LISTENING 5257 2141/cupsd /var/run/cups/cups.sockunix 2 [ ACC ] STREAM LISTENING 5677 2328/hald @/var/run/hald/dbus-gzDLkbe0vzunix 2 [ ACC ] STREAM LISTENING 5678 2328/hald @/var/run/hald/dbus-y2AFY83XQFunix 2 [ ACC ] STREAM LISTENING 4424 1755/python /var/run/audit_eventsunix 2 [ ACC ] STREAM LISTENING 4810 1941/dbus-daemon /var/run/dbus/system_bus_socket我們看到unix-socket程式產生的socket檔案,如下:unix 2 [ ACC ] STREAM LISTENING 8331 2879/unix-socket /tmp/localsockACC:表示這個unix socket程式調用ACCEPT函數,處於接收的狀態.SOCK_STREAM:表示這個unix socket是可靠的基於串連的資料轉送,基本協議保證了按照傳輸的順序讀取資訊.I-NODE:表示通訊端的索引號,就像一個檔案.通過查看/proc/net/unix,也可以看到unix通訊端的資訊.cat /proc/net/unixNum RefCount Protocol Flags Type St Inode Pathd3341040: 00000002 00000000 00010000 0001 01 4899 /var/run/sdpd2893c80: 00000002 00000000 00010000 0001 01 5534 /tmp/.font-unix/fs7100d32dac80: 00000002 00000000 00010000 0001 01 6586 /tmp/ssh-yWORhw2468/agent.2468d32da3c0: 00000002 00000000 00010000 0001 01 8331 /tmp/localsockdb380c80: 00000002 00000000 00010000 0001 01 4988 /var/run/pcscd.commdb380900: 00000002 00000000 00010000 0001 01 5151 /var/run/acpid.socketdb380040: 00000002 00000000 00010000 0001 01 5412 /dev/gpmctld2893200: 00000002 00000000 00010000 0001 01 5631 /var/run/avahi-daemon/socketdb380580: 00000002 00000000 00010000 0001 01 5257 /var/run/cups/cups.sockdfcf4900: 00000012 00000000 00000000 0002 01 4416 /dev/logdfcf4e40: 00000002 00000000 00000000 0002 01 1081 @/org/kernel/udev/udevdd1029580: 00000002 00000000 00000000 0002 01 5686 @/org/freedesktop/hal/udev_eventd1029c80: 00000002 00000000 00010000 0001 01 5677 @/var/run/hald/dbus-gzDLkbe0vzd1029ac0: 00000002 00000000 00010000 0001 01 5678 @/var/run/hald/dbus-y2AFY83XQFdfcf4580: 00000002 00000000 00010000 0001 01 4424 /var/run/audit_eventsd3341c80: 00000002 00000000 00010000 0001 01 4810 /var/run/dbus/system_bus_socket可以通過lsof來查看unix通訊端資訊,如下:netstat -xnpl|grep localsockunix 2 [ ACC ] STREAM LISTENING 8331 2879/unix-socket /tmp/localsocklsof /tmp/localsock COMMAND PID USER FD TYPE DEVICE SIZE NODE NAMEunix-sock 2879 root 3u unix 0xd32da3c0 8331 /tmp/localsock在這裡我們可以看使用者ID,檔案描述符.可以通過查看/proc/8331/fd/,來看檔案描述的資訊,如下:ls -l /proc/2879/fdtotal 0lrwx------ 1 root root 64 Mar 19 01:32 0 -> /dev/pts/0lrwx------ 1 root root 64 Mar 19 01:32 1 -> /dev/pts/0lrwx------ 1 root root 64 Mar 19 01:32 2 -> /dev/pts/0lrwx------ 1 root root 64 Mar 19 01:32 3 -> socket:[8331]對於tcp/udp的SOCKET通訊端,如下:查看tcp的SOCKET通訊端:netstat -tanpActive Internet connections (servers and established)Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:2208 0.0.0.0:* LISTEN 2119/hpiod tcp 0 0 0.0.0.0:779 0.0.0.0:* LISTEN 1869/rpc.statd tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 1830/portmap tcp 0 0 0.0.0.0:23 0.0.0.0:* LISTEN 2177/xinetd tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 2141/cupsd tcp 0 0 127.0.0.1:2207 0.0.0.0:* LISTEN 2124/python tcp 0 0 :::22 :::* LISTEN 2160/sshd tcp 0 0 ::1:631 :::* LISTEN 2141/cupsd tcp 0 148 ::ffff:192.168.27.130:22 ::ffff:192.168.27.1:2892 ESTABLISHED 2468/2 查看udp的SOCKET通訊端:netstat -uanpActive Internet connections (servers and established)Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name udp 0 0 0.0.0.0:32768 0.0.0.0:* 2311/avahi-daemon: udp 0 0 0.0.0.0:773 0.0.0.0:* 1869/rpc.statd udp 0 0 0.0.0.0:776 0.0.0.0:* 1869/rpc.statd udp 0 0 0.0.0.0:68 0.0.0.0:* 1548/dhclient udp 0 0 0.0.0.0:5353 0.0.0.0:* 2311/avahi-daemon: udp 0 0 0.0.0.0:111 0.0.0.0:* 1830/portmap udp 0 0 0.0.0.0:631 0.0.0.0:* 2141/cupsd udp 0 0 :::32769 :::* 2311/avahi-daemon: udp 0 0 :::5353 :::* 2311/avahi-daemon: 通過lsof來查看tcp的資訊.lsof -n -i tcpCOMMAND PID USER FD TYPE DEVICE SIZE NODE NAMEportmap 1830 rpc 4u IPv4 4533 TCP *:sunrpc (LISTEN)rpc.statd 1869 root 7u IPv4 4615 TCP *:779 (LISTEN)hpiod 2119 root 0u IPv4 5185 TCP 127.0.0.1:2208 (LISTEN)python 2124 root 4u IPv4 5201 TCP 127.0.0.1:2207 (LISTEN)cupsd 2141 root 3u IPv6 5255 TCP [::1]:ipp (LISTEN)cupsd 2141 root 4u IPv4 5256 TCP 127.0.0.1:ipp (LISTEN)sshd 2160 root 3u IPv6 5303 TCP *:ssh (LISTEN)xinetd 2177 root 5u IPv4 5416 TCP *:telnet (LISTEN)sshd 2468 root 3u IPv6 6547 TCP 192.168.27.130:ssh->192.168.27.1:snifferdata (ESTABLISHED)通過lsof來查看udp的資訊.lsof -n -i udpCOMMAND PID USER FD TYPE DEVICE SIZE NODE NAMEdhclient 1548 root 4u IPv4 4027 UDP *:bootpc portmap 1830 rpc 3u IPv4 4532 UDP *:sunrpc rpc.statd 1869 root 3u IPv4 4612 UDP *:wpages rpc.statd 1869 root 6u IPv4 4602 UDP *:notify cupsd 2141 root 6u IPv4 5259 UDP *:ipp avahi-dae 2311 avahi 13u IPv4 5635 UDP *:mdns avahi-dae 2311 avahi 14u IPv6 5636 UDP *:mdns avahi-dae 2311 avahi 15u IPv4 5637 UDP *:filenet-tms avahi-dae 2311 avahi 16u IPv6 5638 UDP *:filenet-rpc 在lsof的輸出可以看到檔案描述符及裝置的資訊,另外還有使用者資訊.最後我們來看一下管道和通訊端的INODE,每個檔案都有自己的INODE,但由於VFS(虛擬檔案系統)使所有的檔案系統都通用,使tmpfs/procfs下的檔案像駐留在磁碟上的檔案一樣.INODE儲存著檔案的資料結構,檔案系統中每個對象有一個唯一的INODE.INODE對於沒有檔案名稱的對象,包括socket和管道是非常有用的.TCP/UDP通訊端的INODE,可以用下面的命令來查看:lsof -i tcp -a -p 2468COMMAND PID USER FD TYPE DEVICE SIZE NODE NAMEsshd 2468 root 3u IPv6 6547 TCP 192.168.27.130:ssh->192.168.27.1:snifferdata (ESTABLISHED)其它的DEIVCE就是它的INODE,NODE一欄只顯示TCP下面是UDP通訊端的例子:lsof -i udp -a -p 1869COMMAND PID USER FD TYPE DEVICE SIZE NODE NAMErpc.statd 1869 root 3u IPv4 4612 UDP *:wpages rpc.statd 1869 root 6u IPv4 4602 UDP *:notify 對於UNIX的本地通訊端,可以直接用netstat來查看,如下:netstat -xnpActive UNIX domain sockets (w/o servers)Proto RefCnt Flags Type State I-Node PID/Program name Pathunix 17 [ ] DGRAM 4416 1774/syslogd /dev/logunix 2 [ ] DGRAM 1081 385/udevd @/org/kernel/udev/udevdunix 2 [ ] DGRAM 5686 2328/hald @/org/freedesktop/hal/udev_event而對於管道,可以在/proc/pid/fd和lsof -p pid的方式來查看INODE