从accept返回的文件描述符中获取IP地址的C socket方法

12

我知道这个问题似乎很普通,并且已经回答了多次,但我认为如果你阅读细节,它并不那么常见(我没有找到它)。

关键是,我正在开发一个在C语言中打开套接字的Unix服务,并等待连接,当我有一个连接时,我创建一个新进程来处理它,所以可以同时打开多个连接

int newfd = accept(sockfd, (struct sockaddr *)&clientaddr, (socklen_t*)&clientaddr_size);

稍后(在其他方法和代码之后内部)子进程将连接信息保存到BBDD,我还需要在那个确切的时刻获取打开该连接的IP地址。

由于可能同时存在多个连接,而我传递给accept方法的变量struct sockaddr_in clientaddr所有进程共享,所以我不确定后来从那种方式获取IP地址信息是否是一个好主意,因为那样我可能会得到另一个已经打开的连接的IP地址

我想能否从accept方法获得的文件描述符int newfd访问IP地址(返回的整数)。这是否可能?或者我误解了文件描述符函数?


2
谢谢@alk,我看到它们非常相似,尽管(肯定是因为我的英语),我不需要绑定地址,我需要客户端地址。现在我已经看到了使用getpeername()方法的类似方式 :) - Aleix
啊,我明白了。所以你可能想要给自己的问题添加一个答案,甚至接受它。 - alk
可能是获取远程地址/IP - C Berkeley套接字的重复问题。 - Joseph Quinsey
好的。这个是对的@JosephQuinsey,相等且更简单。抱歉之前我没找到它... - Aleix
4个回答

27

好的。感谢@alk和@rileyberton,我找到了正确的使用方法,即getpeername

int sockfd;

void main(void) {
    //[...]
    struct sockaddr_in clientaddr;
    socklen_t clientaddr_size = sizeof(clientaddr);
    int newfd = accept(sockfd, (struct sockaddr *)&clientaddr, &clientaddr_size);
    //fork() and other code
    foo(newfd);
    //[...]
}
void foo(int newfd) {
    //[...]
    struct sockaddr_in addr;
    socklen_t addr_size = sizeof(struct sockaddr_in);
    int res = getpeername(newfd, (struct sockaddr *)&addr, &addr_size);
    char *clientip = new char[20];
    strcpy(clientip, inet_ntoa(addr.sin_addr));
    //[...]
}

现在我可以通过另一个过程来获取客户端的IP地址(在“string”clientip中),只需携带使用accept方法获得的文件描述符newfd


不要将addr_size声明为int,而应该声明为socklen_t。在调用getpeername()时将int*强制转换为socklen_t*可能会隐藏问题,因为socklen_t的大小可能与int不同。对于调用accept()也是如此。 - alk
1
完成了!我已经在accept()方法的调用中进行了更改。非常感谢您的建议 :) - Aleix

3

谢谢@rileyberton,对我来说正确的方法是getpeername()(http://linux.die.net/man/2/getpeername) 我可以看到这篇文章非常相似,但是进程之间的讨论有点混乱:P - Aleix
绑定套接字的IP地址不是他要求的。请仔细阅读问题。 - user207421

0
发现这个有用 例子 这是我的做法
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h> 

int main(int argc, char *argv[])
{
    int listenfd = 0, connfd = 0;
    struct sockaddr_in serv_addr; 
    socklen_t len; 


    char sendBuff[1025];

    time_t ticks; 

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&serv_addr, '0', sizeof(serv_addr));
    memset(sendBuff, '0', sizeof(sendBuff)); 

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(5000); 

    bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 

    listen(listenfd, 10); 

    while(1)
    {
        connfd = accept(listenfd, (struct sockaddr*)NULL, NULL); 

        ticks = time(NULL);
        snprintf(sendBuff, sizeof(sendBuff), "%.24s\r\n", ctime(&ticks));
        printf("%d \n",connfd);
        
        getpeername(connfd, (struct sockaddr*)&serv_addr, &len );
        printf("Peer connected %s:%d\n", inet_ntoa(serv_addr.sin_addr),ntohs(serv_addr.sin_port));

        write(connfd, sendBuff, strlen(sendBuff)); 

        close(connfd);
        sleep(1);
     }
}


0

有状态连接由两个端点唯一标识:Peer(address:port)<=>My(address:port)。需要使用getpeername()和getsockname()来获取此信息。


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