您的位置:首页 > 运维架构 > Linux

linux管道与套接字的调试工具

2011-10-01 20:16 495 查看
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 =27695
parentpid = 27694

程序会在父进程执行时调用sleep(30),此时子进程已经完成对管道的写入,并关闭了子进程的管道(读/写两端).
父进程在sleep(30)秒后,从管道读取信息并输出.

我们在父进程睡眠的时候,根据它的parentpid输出,来查看它的文件描述符,如下:

ls -l /proc/27694/fd
total 0
lrwx------ 1 root root 64 Mar 18 13:06 0 -> /dev/pts/0
lrwx------ 1 root root 64 Mar 18 13:06 1 -> /dev/pts/0
lrwx------ 1 root root 64 Mar 18 13:06 2 -> /dev/pts/0
lr-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 43046
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
pipe 27780 root 3r FIFO 0,6 43046 pipe
pipe 27780 root 4w FIFO 0,6 43046 pipe

2)套接字的调试

调试套接字时两个最有用的工具是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 -nlxp
Active UNIX domain sockets (only servers)
Proto RefCnt Flags Type State I-Node PID/Program name Path
unix 2 [ ACC ] STREAM LISTENING 4899 1967/sdpd /var/run/sdp
unix 2 [ ACC ] STREAM LISTENING 5534 2260/xfs /tmp/.font-unix/fs7100
unix 2 [ ACC ] STREAM LISTENING 6586 2468/1 /tmp/ssh-yWORhw2468/agent.2468
unix 2 [ ACC ] STREAM LISTENING 8331 2879/unix-socket /tmp/localsock
unix 2 [ ACC ] STREAM LISTENING 4988 2030/pcscd /var/run/pcscd.comm
unix 2 [ ACC ] STREAM LISTENING 5151 2103/acpid /var/run/acpid.socket
unix 2 [ ACC ] STREAM LISTENING 5412 2206/gpm /dev/gpmctl
unix 2 [ ACC ] STREAM LISTENING 5631 2311/avahi-daemon: /var/run/avahi-daemon/socket
unix 2 [ ACC ] STREAM LISTENING 5257 2141/cupsd /var/run/cups/cups.sock
unix 2 [ ACC ] STREAM LISTENING 5677 2328/hald @/var/run/hald/dbus-gzDLkbe0vz
unix 2 [ ACC ] STREAM LISTENING 5678 2328/hald @/var/run/hald/dbus-y2AFY83XQF
unix 2 [ ACC ] STREAM LISTENING 4424 1755/python /var/run/audit_events
unix 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/localsock

ACC:表示这个unix socket程序调用ACCEPT函数,处于接收的状态.
SOCK_STREAM:表示这个unix socket是可靠的基于连接的数据传输,基本协议保证了按照传输的顺序读取信息.
I-NODE:表示套接字的索引号,就像一个文件.

通过查看/proc/net/unix,也可以看到unix套接字的信息.
cat /proc/net/unix
Num RefCount Protocol Flags Type St Inode Path
d3341040: 00000002 00000000 00010000 0001 01 4899 /var/run/sdp
d2893c80: 00000002 00000000 00010000 0001 01 5534 /tmp/.font-unix/fs7100
d32dac80: 00000002 00000000 00010000 0001 01 6586 /tmp/ssh-yWORhw2468/agent.2468
d32da3c0: 00000002 00000000 00010000 0001 01 8331 /tmp/localsock
db380c80: 00000002 00000000 00010000 0001 01 4988 /var/run/pcscd.comm
db380900: 00000002 00000000 00010000 0001 01 5151 /var/run/acpid.socket
db380040: 00000002 00000000 00010000 0001 01 5412 /dev/gpmctl
d2893200: 00000002 00000000 00010000 0001 01 5631 /var/run/avahi-daemon/socket
db380580: 00000002 00000000 00010000 0001 01 5257 /var/run/cups/cups.sock
dfcf4900: 00000012 00000000 00000000 0002 01 4416 /dev/log
dfcf4e40: 00000002 00000000 00000000 0002 01 1081 @/org/kernel/udev/udevd
d1029580: 00000002 00000000 00000000 0002 01 5686 @/org/freedesktop/hal/udev_event
d1029c80: 00000002 00000000 00010000 0001 01 5677 @/var/run/hald/dbus-gzDLkbe0vz
d1029ac0: 00000002 00000000 00010000 0001 01 5678 @/var/run/hald/dbus-y2AFY83XQF
dfcf4580: 00000002 00000000 00010000 0001 01 4424 /var/run/audit_events
d3341c80: 00000002 00000000 00010000 0001 01 4810 /var/run/dbus/system_bus_socket

可以通过lsof来查看unix套接字信息,如下:

netstat -xnpl|grep localsock
unix 2 [ ACC ] STREAM LISTENING 8331 2879/unix-socket /tmp/localsock

lsof /tmp/localsock
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
unix-sock 2879 root 3u unix 0xd32da3c0 8331 /tmp/localsock

在这里我们可以看用户ID,文件描述符.

可以通过查看/proc/8331/fd/,来看文件描述的信息,如下:
ls -l /proc/2879/fd
total 0
lrwx------ 1 root root 64 Mar 19 01:32 0 -> /dev/pts/0
lrwx------ 1 root root 64 Mar 19 01:32 1 -> /dev/pts/0
lrwx------ 1 root root 64 Mar 19 01:32 2 -> /dev/pts/0
lrwx------ 1 root root 64 Mar 19 01:32 3 -> socket:[8331]

对于tcp/udp的SOCKET套接字,如下:

查看tcp的SOCKET套接字:
netstat -tanp
Active 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 -uanp
Active 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 tcp
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
portmap 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 udp
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
dhclient 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 2468
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
sshd 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 1869
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
rpc.statd 1869 root 3u IPv4 4612 UDP *:wpages
rpc.statd 1869 root 6u IPv4 4602 UDP *:notify

对于UNIX的本地套接字,可以直接用netstat来查看,如下:
netstat -xnp
Active UNIX domain sockets (w/o servers)
Proto RefCnt Flags Type State I-Node PID/Program name Path
unix 17 [ ] DGRAM 4416 1774/syslogd /dev/log
unix 2 [ ] DGRAM 1081 385/udevd @/org/kernel/udev/udevd
unix 2 [ ] DGRAM 5686 2328/hald @/org/freedesktop/hal/udev_event

而对于管道,可以在/proc/pid/fd和lsof -p pid的方式来查看INODE
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: