如何在Linux中列出活动端口和使用它们的进程,C代码

3

我正在尝试编写一段C代码,以完成与以下相同的工作:

netstat -vatp

列出所有远程/本地地址和使用它们的进程。但我不知道应该读哪些文件?
我尝试查看 /proc/net/tcp 和 /proc/net/udp,但它们没有像 netstat 显示的进程名称或进程标识符!
谢谢。

4
我建议你深入研究netstat的代码! - clyfe
1
你可以使用 straceltrace 来了解它的功能。 - Basile Starynkevitch
2个回答

4
您可以查看源代码http://freecode.com/projects/net-tools。只需下载,解压缩bz2文件,您就会找到netstat.c源代码。
快速分析:
例如,/proc/net/tcp有一个inode表,在/proc中有一个子文件夹对应每个这些inodes,其中包含您需要的信息。
更多分析:
我认为情况甚至更糟。 netstat只是循环遍历/proc目录并检查数字子目录的内容以查找与inode匹配的实际进程。不确定,因为我只是在分析。 http://linux.die.net/man/5/proc非常好读:)
有关您的答案,请参见如何将每个/proc/net/tcp条目与每个打开的套接字匹配?

对不起,我该如何打开一个inode并检查它的所有权?只需要API名称,我会完成剩下的部分。谢谢 - killercode
只需查看prg_cache_load()函数即可了解netstat()的功能。 - Matthias van der Vlies
好的,这是我得到的内容,请纠正我如果我错了。 netstat打开/proc目录,进入每个进程目录,并进入/proc/<pid>/fd目录,读取所有链接,然后将每个链接添加到链表中,该链接就是我要查找的inode? - killercode
好的,我有点困惑,它可能是一个链接,也可能不是?还是它总是一个链接,我只需要一直使用 readlink 命令? - killercode
netstat 使用 readlink,在 /proc/<pid>/fd 目录中,文件描述符(命名)是从 1 -> <N> 的,所以它必须是他们的链接,因为 inode 值大多数情况下超过了 3000。我想是这样? - killercode
显示剩余2条评论

2

您可以在代码中调用netstat应用程序。查看execve以捕获stdout和stderr。

编辑: 因为代码比语言更能说明问题:

IEFTask.h

#ifndef IEFTASK_H
#define IEFTASK_H

#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <signal.h>
#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* MARK: Structure */
struct IEFTask {
    const char **arguments; /* last argument should be NULL */
    int standardInput;
    void *callbackArgument;

    void (*callback)(int term, char *out, size_t outLen, 
        char *err, size_t errLen, void *arg);
};
typedef struct IEFTask IEFTask;

/* MARK: Running */
int
IEFTaskRun(IEFTask *theTask);

#endif /* IEFTASK_H */

IEFTask.c

#include "IEFTask.h"

/* MARK: DECLARATION: Data Conversion */
char *
IEFTaskCreateBufferFromPipe(int fd, size_t *bufLen);

/* MARK: Running */
int
IEFTaskRun(IEFTask *myTask) {
    pid_t pid;
    int exitStatus, status;
    int outPipe[2], errPipe[2];

    assert(myTask != NULL);

    /* Create stdout and stderr pipes */
    {
        status = pipe(outPipe);
        if(status != 0) {
            return -1;
        }

        status = pipe(errPipe);
        if(status != 0) {
            close(errPipe[0]);
            close(errPipe[1]);
            return -1;
        }
    }

    /* Fork the process and wait pid */
    {

        pid = fork();

        if(pid < 0) { /* error */
            return -1;

        } else if(pid > 0) { /* parent */
            waitpid(pid, &exitStatus, 0);
            exitStatus = WEXITSTATUS(exitStatus);

        } else { /* child */
            /* close unneeded pipes */
            close(outPipe[0]);
            close(errPipe[0]);

            /* redirect stdout, stdin, stderr */
            if(myTask->standardInput >= 0) {
                close(STDIN_FILENO);
                dup2(myTask->standardInput, STDIN_FILENO);
                close(myTask->standardInput);
            }

            close(STDOUT_FILENO);
            dup2(outPipe[1], STDOUT_FILENO);
            close(outPipe[1]);

            close(STDERR_FILENO);
            dup2(errPipe[1], STDERR_FILENO);
            close(errPipe[1]);

            execve(myTask->arguments[0], 
                (char *const *)myTask->arguments, NULL);
            exit(127);
        }
    }

    /* Parent continues */
    {
        char *output, *error;
        size_t outLen, errLen;

        /* 127 = execve failed */
        if(exitStatus == 127) {
            close(errPipe[0]);
            close(errPipe[1]);
            close(outPipe[0]);
            close(outPipe[1]);
            return -1;
        }

        /* Read in data */
        close(errPipe[1]);
        close(outPipe[1]);

        output = IEFTaskCreateBufferFromPipe(outPipe[0], &outLen);
        error = IEFTaskCreateBufferFromPipe(errPipe[0], &errLen);

        close(errPipe[0]);
        close(outPipe[0]);

        /* Call callback */
        (*myTask->callback)(exitStatus, 
            output, outLen,
            error, errLen, myTask->callbackArgument);

        if(output) free(output);
        if(error) free(error);
    }

    return 0;
}

/* MARK: Data Conversion */
#define READ_BUF_SIZE (128)
char *
IEFTaskCreateBufferFromPipe(int fd, size_t *bufLen) {
    ssize_t totalRead = 0, nowRead;
    char readBuffer[READ_BUF_SIZE], *myBuffer = NULL;
    char *ptr;

    while(1) {
        nowRead = read(fd, readBuffer, READ_BUF_SIZE);
        if(nowRead == -1) {
            free(myBuffer);
            return NULL;

        } else if(nowRead == 0) {
            break;

        } else {
            ptr = realloc(myBuffer, totalRead + nowRead);
            if(ptr == NULL) {
                free(myBuffer);
                return NULL;
            }
            myBuffer = ptr;
            memcpy(&(myBuffer[totalRead]), readBuffer, nowRead);
            totalRead += nowRead;
        }
    }

    if(bufLen) *bufLen = (size_t)totalRead;

    return myBuffer;
}

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "IEFTask.h"


void taskCallback(int term,
    char *out, size_t outlen,
    char *err, size_t errlen)
{
    char *ptr;
    printf("Task terminated: %d\n", term);

    ptr = malloc(outlen + 1);
    memcpy(ptr, out, outlen);
    ptr[outlen] = '\0';
    printf("***STDOUT:\n%s\n***END\n", ptr);
    free(ptr);

    ptr = malloc(errlen + 1);
    memcpy(ptr, err, errlen);
    ptr[errlen] = '\0';
    printf("***STDERR:\n%s\n***END\n", ptr);
    free(ptr);
}

int main() {
    const char *arguments[] = {
        "/bin/echo",
        "Hello",
        "World",
        NULL
    };

    IEFTask myTask;
    myTask.arguments = arguments;
    myTask.standardInput = -1;
    myTask.callback = &taskCallback;

    int status;
    status = IEFTaskRun(&myTask);

    if(status != 0) {
        printf("Failed: %s\n", strerror(errno));
    }

    return 0;
}

execve无法帮助捕获stdout;发帖者可能需要使用popenpipe+fork+dup2+execve - Basile Starynkevitch
嗯,是的,这就是我想的,但我认为这是不言自明的。我编辑了我的答案并附加了一个示例。 - v1Axvw
非常有用,这可能是我在其他无法编码的东西上的最后一招,非常感谢。 - killercode

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接