如何确定客户端是否已连接到我的套接字?

How can I determine if clients are connected to my socket?

我有代码调用打开 TCP 服务器套接字的库(在本例中为 gstreamer)。我有端口号,但我无权访问文件描述符。

我想从我的应用程序中检测当前是否有客户端连接到此端口。理想情况下,我想要一种跨平台方法(Linux + Mac,*BSD 加分)。

我知道 netstat 可以帮助我做到这一点,但我想要一种编程技术。

在 Serhio 上扩展。如果你打开 /proc//net/tcp 并阅读它,你会看到:

 sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode                                                     
   0: 0100007F:0CEA 00000000:0000 0A 00000000:00000000 00:00000000 00000000   116        0 14581 1 ffff880406690000 100 0 0 10 0                     
   1: 00000000:008B 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 15646 1 ffff880404aa8700 100 0 0 10 0                     
   2: 0100007F:13AD 00000000:0000 0A 00000000:00000000 00:00000000 00000000  1000        0 16859998 1 ffff880406692a00 100 0 0 10 0                  
   3: 0100007F:F76E 00000000:0000 0A 00000000:00000000 00:00000000 00000000  1000        0 31381008 1 ffff8800d7926200 100 0 0 10 0  
...

来自过程 manpage:

 /proc/net/tcp
              Holds a dump of the TCP socket table.  Much of the information
              is not of use apart from debugging.  The "sl" value is the
              kernel hash slot for the socket, the "local_address" is the
              local address and port number pair.  The "rem_address" is the
              remote address and port number pair (if connected).  "St" is
              the internal status of the socket.  The "tx_queue" and
              "rx_queue" are the outgoing and incoming data queue in terms
              of kernel memory usage.  The "tr", "tm->when", and "rexmits"
              fields hold internal information of the kernel socket state
              and are useful only for debugging.  The "uid" field holds the
              effective UID of the creator of the socket.

因此,解析这些行(跳过第一行,然后是 sscanf)并从 local_address 字段中提取端口号以找到您感兴趣的端口。查看 st 字段以在连接状态。如果您发现任何东西处于连接状态,return 为真。

库代码在您进程的地址space中运行。它使用的文件描述符只是 int 值,您可以使用 getsockopt() 找到 TCP/IP 套接字,然后在这些套接字上使用 getpeername() 找到连接的套接字。根据 POSIX 文档 for getsockopt() and getpeername():

#include <sys/socket.h>

// probably better to use getrlimit() here...
#define MAX_FD 1024

int tcp_socket_fds[ MAX_FD ];
struct sockaddr_in peers[ MAX_FD ];

for ( int fd = 0; fd < MAX_FD; fd++ )
{
    int type;
    int len = sizeof( type );

    int rc = getsockopt( fd, SOL_SOCKET, SO_TYPE, &type, &len );    
    if ( ( 0 == rc ) && ( SOCK_STREAM == type ) )
    {
        tcp_socket_fds[ fd ] = 1;

        socklen_t socket_len = sizeof( peers[ fd ] );
        rc = getpeername( fd, &( peers[ fd ] ), &socket_len );

        // zero out the peer if getpeername() failed
        if ( 0 != rc )
        {
            memset( &( peers[ fd ], 0, sizeof( peers[ fd ] ) );
        }
    }
    else
    {
        tcp_socket_fds[ fd ] = 0;
    }
}

这将找到您的进程在检查时打开的所有连接的 TCP 套接字,它应该是相当可移植的。