首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么getsockopt optlen是零?

为什么getsockopt optlen是零?
EN

Stack Overflow用户
提问于 2020-09-18 20:42:14
回答 2查看 181关注 0票数 0

我使用非阻塞套接字和事件库。我只是注意到,当我快速调用连接到本地ip的端口时,getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &optlen);的optlen变成0。

我试着做更小的代码来显示问题。我在这段代码中使用了epoll,但在其他事件库中也会出现同样的问题。

代码语言:javascript
复制
#define nconnect_d 500
#define ebuffer_d 64

#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>

struct sockaddr_in initaddr(uint32_t ip, uint16_t port){
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = htonl(ip);
    memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
    return addr;
}

int getconnectfd(uint32_t sip, uint16_t sport, uint32_t dip, uint16_t dport){
    int fd;
    if((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
        return -1;
    if(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (int[]){1}, sizeof(int)) == -1)
        return -1;
    if(fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) == -1)
        return -1;
    struct sockaddr_in saddr = initaddr(sip, sport);
    if(bind(fd, (const struct sockaddr *)&saddr, (socklen_t)sizeof(struct sockaddr_in)) == -1)
        return -1;
    struct sockaddr_in daddr = initaddr(dip, dport);
    if(connect(fd, (const struct sockaddr*)&daddr, (socklen_t)sizeof(struct sockaddr_in)) == -1 && errno != EINPROGRESS)
        return -1;
    return fd;
}

int epolltouch(int efd, int sfd, uint32_t flag){
    struct epoll_event event;
    event.data.fd = sfd;
    event.events = flag;
    if(epoll_ctl(efd, EPOLL_CTL_ADD, sfd, &event) == -1)
        return -1;
    return 0;
}

int epollrm(int efd, int sfd){
    if(epoll_ctl(efd, EPOLL_CTL_DEL, sfd, NULL) == -1)
        return -1;
    return 0;
}

int main(){
    int efd = epoll_create1(0);
    assert(efd != -1);
    for(uint32_t i = 0; i < nconnect_d; i++){
        int sfd = getconnectfd(INADDR_ANY, 12420, 0x7f000001, 2048 + i);
        assert(sfd != -1);
        epolltouch(efd, sfd, EPOLLOUT | EPOLLET);
    }
    struct epoll_event events[ebuffer_d];
    uint32_t iconnect = nconnect_d;
    while(iconnect){
        int n = epoll_wait(efd, events, ebuffer_d, -1);
        assert(n != -1);
        for(uint32_t i = 0; i < n; i++){
            int evfd = events[i].data.fd;
            int opt, optlen;
            assert(getsockopt(evfd, SOL_SOCKET, SO_ERROR, &opt, &optlen) != -1);
            assert(optlen == sizeof(int));
            switch(opt){
                case 0:{
                    /* connection has been established */
                    break;
                }
                case ECONNREFUSED:
                case EHOSTUNREACH:
                case ENETUNREACH:
                /* can be more valid case isn't it? */
                {
                    /* connection has failed */
                    break;
                }
                default:{
                    assert(0);
                }
            }
            iconnect--;
            epollrm(efd, evfd);
            close(evfd);
        }
    }
    return 0;
}

当我奔跑的时候;

代码语言:javascript
复制
$ ./a.out
a.out: temp.c:72: main: Assertion `optlen == sizeof(int)' failed.
Aborted (core dumped)

optlen 0是否意味着套接字因某种原因而关闭?之后我们需要关闭套接字吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-09-18 20:55:58

调用getsockopt()需要向系统提供缓冲区,这意味着必须在调用之前设置optlen

代码语言:javascript
复制
int opt;
socklen_t optlen = sizeof opt;

... getsockopt(evfd, SOL_SOCKET, SO_ERROR, &opt, &optlen);

通过这种方式,getsockopt()知道允许它写入“缓冲区”(在本例中只是一个整数)中的允许量,并且它用实际写入的字节数更新optlen

手册页注意到,optlen是一个值/结果,这意味着您设置它并期望得到另一个值,但是opt只是一个结果,所以不关心其中的值是什么。

编辑将optlen的类型固定为socklen_t,h/t为prog-fh。

票数 2
EN

Stack Overflow用户

发布于 2020-09-18 20:57:45

使用getsockopt()时,最后一个参数必须是初始化的 socklen_t的地址。在调用之前,您应该使用存储的大小初始化它,以获得结果值(sizeof(opt)在这里)。它是通过地址传递的,因为如果这个存储空间对于实际结果来说太大了,那么系统调用就会将它调整到这个精确的大小。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63962595

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档