连接到套接字时似乎无法正常工作

点头

我正在尝试为connect()提供超时。我四处搜寻,并找到了与此相关的几篇文章。我已经编码了我认为应该可以工作的代码,但是不幸的是我没有从getsockopt()报告任何错误。但是,当我进入write()时,它的错误号为107-ENOTCONN。

有两点。我正在Fedora 23上运行。connect()的文档说,它应该返回错误,错误码为EINPROGRESS,表示连接尚未完成,但是我遇到了EAGAIN,所以我在检查中添加了它。当前,我的套接字服务器在listen()调用中将积压设置为零。许多调用成功,但失败的调用都因我在write()调用中提到的107-ENOTCONN而失败。

我希望我只是想念一些东西,但到目前为止还不知道是什么。

int domain_socket_send(const char* socket_name, unsigned char* buffer,
        unsigned int length, unsigned int timeout)
{
    struct sockaddr_un addr;
    int fd = -1;
    int result = 0;

    // Create socket.

    fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (fd == -1)
        {
        result = -1;
        goto done;
        }

    if (timeout != 0)
        {

        // Enabled non-blocking.

        int flags;
        flags = fcntl(fd, F_GETFL);
        fcntl(fd, F_SETFL, flags | O_NONBLOCK);
        }

    // Set socket name.

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, socket_name, sizeof(addr.sun_path) - 1);

    // Connect.

    result = connect(fd, (struct sockaddr*) &addr, sizeof(addr));
    if (result == -1)
        {

        // If some error then we're done.

        if ((errno != EINPROGRESS) && (errno != EAGAIN))
            goto done;

        fd_set write_set;
        struct timeval tv;

        // Set timeout.

        tv.tv_sec = timeout / 1000000;
        tv.tv_usec = timeout % 1000000;

        unsigned int iterations = 0;
        while (1)
            {
            FD_ZERO(&write_set);
            FD_SET(fd, &write_set);

            result = select(fd + 1, NULL, &write_set, NULL, &tv);
            if (result == -1)
                goto done;
            else if (result == 0)
                {
                result = -1;
                errno = ETIMEDOUT;
                goto done;
                }
            else
                {
                if (FD_ISSET(fd, &write_set))
                    {
                    socklen_t len;
                    int socket_error;
                    len = sizeof(socket_error);

                    // Get the result of the connect() call.

                    result = getsockopt(fd, SOL_SOCKET, SO_ERROR,
                            &socket_error, &len);
                    if (result == -1)
                        goto done;

                    // I think SO_ERROR will be zero for a successful
                    // result and errno otherwise.

                    if (socket_error != 0)
                        {
                        result = -1;
                        errno = socket_error;
                        goto done;
                        }

                    // Now that the socket is writable issue another connect.

                    result = connect(fd, (struct sockaddr*) &addr,
                            sizeof(addr));
                    if (result == 0)
                        {
                        if (iterations > 1)
                            {
                            printf("connect() succeeded on iteration %d\n",
                                    iterations);
                            }
                        break;
                        }
                    else
                        {
                        if ((errno != EAGAIN) && (errno != EINPROGRESS))
                            {
                            int err = errno;
                            printf("second connect() failed, errno = %d\n",
                                    errno);
                            errno = err;
                            goto done;
                            }
                        iterations++;
                        }
                    }
                }
            }
        }

    // If we put the socket in non-blocking mode then put it back
    // to blocking mode.

    if (timeout != 0)
        {

        // Turn off non-blocking.

        int flags;
        flags = fcntl(fd, F_GETFL);
        fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
        }

    // Write buffer.

    result = write(fd, buffer, length);
    if (result == -1)
        {
        int err = errno;
        printf("write() failed, errno = %d\n", err);
        errno = err;
        goto done;
        }

done:
    if (result == -1)
        result = errno;
    else
        result = 0;
    if (fd != -1)
        {
        shutdown(fd, SHUT_RDWR);
        close(fd);
        }
    return result;
}

更新04/05/2016:

我突然意识到也许我需要多次调用connect()直到成功,毕竟这是非阻塞io而不是异步io。就像在遇到read()上的EAGAIN后要读取的数据时,我必须再次调用read()一样。另外,我发现了以下SO问题:

对非阻塞套接字使用select()总是返回1

在EJP的答案中,您需要发出多个connect()。另外,从EJP书中引用:

https://books.google.com/books?id=6H9AxyFd0v0C&pg=PT681&lpg=PT681&dq=stevens+and+wright+tcp/ip+illustrated+non-blocking+connect&source=bl&ots=b6kQar6SdM&sig=kt5xZubPZ2Av7B1Q7AbVQ2A1E1&UxBhQ2A1E2E7B4E1B&Q2B1E1B&Q2A1E1E0E0E0E0&B美国官方网站v = onepage&q = stevens%20and%20wright%20tcp%2Fip%20illustrated%20non-blocking%20connect&f = false

它似乎表明您需要发出多个connect()。我修改了此问题中的代码段,以调用connect()直到成功。我可能仍然需要进行更改,以更新传递给select()的超时值,但这不是我的直接问题。

多次调用connect()似乎已解决了我原来的问题,那是我在调用write()时得到了ENOTCONN,我想是因为套接字未连接。但是,从代码中可以看到,我正在跟踪遍历select循环的次数,直到connect()成功为止。我已经看到了成千上万的数字。这让我担心自己处于繁忙的等待循环中。为什么即使套接字未处于connect()成功状态,它仍可写?是否正在调用connect()清除该可写状态,并且由于某种原因OS再次设置了该可写状态,还是我真的处于繁忙的等待循环中?

谢谢,尼克

点头

http://lxr.free-electrons.com/source/net/unix/af_unix.c中

441 static int unix_writable(const struct sock *sk)
442 {
443         return sk->sk_state != TCP_LISTEN &&
444                (atomic_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf;
445 }

我不确定正在比较哪些缓冲区,但是很明显没有检查套接字的连接状态。因此,除非套接字连接后修改了这些缓冲区,否则我的unix套接字将始终被标记为可写,因此,我无法使用select()来确定无阻塞connect()完成的时间。

并基于http://lxr.free-electrons.com/source/net/unix/af_unix.c中的代码段

1206 static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
1207                                int addr_len, int flags)
.
.
.
1230         timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
.
.
.
1271         if (unix_recvq_full(other)) {
1272                 err = -EAGAIN;
1273                 if (!timeo)
1274                         goto out_unlock;
1275 
1276                 timeo = unix_wait_for_peer(other, timeo);
.
.
.

似乎设置发送超时可能能够使连接超时。该文件还与http://man7.org/linux/man-pages/man7/socket.7.html上的SO_SNDTIMEO文档相匹配

谢谢,尼克

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

通过套接字的iOS连接无法正常工作

来自分类Dev

Docker MySQL无法连接到套接字

来自分类Dev

节点-连接到套接字时的ENONET

来自分类Dev

连接到VPN时iTunes Airplay无法正常工作

来自分类Dev

连接到OpenVPN时FTP无法正常工作

来自分类Dev

运行Rails时无法通过ubuntu中的套接字连接到本地MySQL服务器

来自分类Dev

为什么在删除/tmp/.java_pid <num>套接字文件时jstack无法正常工作

来自分类Dev

套接字无法连接到本地主机

来自分类Dev

超时后无法重新连接到套接字

来自分类Dev

Flutter无法连接到套接字服务器

来自分类Dev

PHP:无法从php-fpm连接到套接字

来自分类Dev

无法通过套接字连接到其他设备

来自分类Dev

连接到抽象UNIX套接字时出现“权限被拒绝”

来自分类Dev

连接到Redis时,Unix套接字比TCP慢

来自分类Dev

连接到云 SQL 时收到套接字错误

来自分类Dev

Application Insights无法正常工作-套接字异常

来自分类Dev

Node.js-套接字断开事件无法正常工作

来自分类Dev

通过套接字接收信息无法正常工作

来自分类Dev

使用套接字的C#委托无法正常工作

来自分类Dev

无法连接到Mir:无法连接到服务器套接字:无此类文件或目录

来自分类Dev

Flutter套接字IO无法连接到Node JS套接字IO服务器

来自分类Dev

Xamarin/WinForms 客户端在双线程体系结构中发送/接收时无法连接到套接字

来自分类Dev

套接字连接被拒绝:telnet:无法连接到远程主机:连接被拒绝

来自分类Dev

用SaltStack解决:initctl:无法连接到Upstart:无法连接到套接字/ com / ubuntu / upstart:连接被拒绝。

来自分类Dev

导入 html 节点时,似乎无法让 PHP appendChild 正常工作

来自分类Dev

Python套接字无法连接

来自分类Dev

无法建立套接字连接

来自分类Dev

套接字无法建立连接

来自分类Dev

连接到VPN的Homestead Vagrant无法正常工作

Related 相关文章

  1. 1

    通过套接字的iOS连接无法正常工作

  2. 2

    Docker MySQL无法连接到套接字

  3. 3

    节点-连接到套接字时的ENONET

  4. 4

    连接到VPN时iTunes Airplay无法正常工作

  5. 5

    连接到OpenVPN时FTP无法正常工作

  6. 6

    运行Rails时无法通过ubuntu中的套接字连接到本地MySQL服务器

  7. 7

    为什么在删除/tmp/.java_pid <num>套接字文件时jstack无法正常工作

  8. 8

    套接字无法连接到本地主机

  9. 9

    超时后无法重新连接到套接字

  10. 10

    Flutter无法连接到套接字服务器

  11. 11

    PHP:无法从php-fpm连接到套接字

  12. 12

    无法通过套接字连接到其他设备

  13. 13

    连接到抽象UNIX套接字时出现“权限被拒绝”

  14. 14

    连接到Redis时,Unix套接字比TCP慢

  15. 15

    连接到云 SQL 时收到套接字错误

  16. 16

    Application Insights无法正常工作-套接字异常

  17. 17

    Node.js-套接字断开事件无法正常工作

  18. 18

    通过套接字接收信息无法正常工作

  19. 19

    使用套接字的C#委托无法正常工作

  20. 20

    无法连接到Mir:无法连接到服务器套接字:无此类文件或目录

  21. 21

    Flutter套接字IO无法连接到Node JS套接字IO服务器

  22. 22

    Xamarin/WinForms 客户端在双线程体系结构中发送/接收时无法连接到套接字

  23. 23

    套接字连接被拒绝:telnet:无法连接到远程主机:连接被拒绝

  24. 24

    用SaltStack解决:initctl:无法连接到Upstart:无法连接到套接字/ com / ubuntu / upstart:连接被拒绝。

  25. 25

    导入 html 节点时,似乎无法让 PHP appendChild 正常工作

  26. 26

    Python套接字无法连接

  27. 27

    无法建立套接字连接

  28. 28

    套接字无法建立连接

  29. 29

    连接到VPN的Homestead Vagrant无法正常工作

热门标签

归档