【计算机网络】网络编程接口 Socket API 解读(4)

这篇具有很好参考价值的文章主要介绍了【计算机网络】网络编程接口 Socket API 解读(4)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

         Socket 是网络协议栈暴露给编程人员的 API,相比复杂的计算机网络协议,API 对关键操作和配置数据进行了抽象,简化了程序编程。

        本文讲述的 socket 内容源自 Linux man。本文主要对各 API 进行详细介绍,从而更好的理解 socket 编程。


listen

poll()           遵循 POSIX.1 - 2008

ppoll()         遵循 Linux

1.库

标准 c 库,libc, -lc

2.头文件

<sys/socket.h>

3.接口定义

       int listen(int sockfd, int backlog);

4.接口描述

        listen() 标记 sockfd 指定的 socket 为被动(passive)socket,也就是说 socket 通过 accept() 来接收进来的连接请求。

        sockfd 参数是一个指向 SOCK_STREAM 或者 SOCK_SEQPACKET 类型的文件描述符。

        backlog 参数定义了在 sockfd 上可以排队的最大长度,如果一个连接请求到达时队列已满,那么客户端会收到一个 ECONNREFUSED 错误,或者如果底层协议支持重传,那么该请求会被忽略从而导致客户端连接重试可能会成功。

5.返回值

        成功时,返回值是 0。

        发生错误时,返回 -1,并设置errno 来指示错误类型。

        错误值定义如下:

EADDRINUSE 另一个 socket 已经监听了同样的端口
EADDRINUSE (网络 domain socket)sockfd 指向的 socket没有绑定到一个地址,尝试绑定到临时端口时,临时端口用尽了
EBADF sockfd 不是一个有效的文件描述符
ENOTSOCK sockfd 文件描述符没有指向一个 socket
EOPNOTSUPP socket 不是支持 listen() 操作的socket

6.注意

       为了接收连接,需要进行以下步骤:

        (1)通过 socket() 接口创建 socket。

        (2)通过 bing() 将 socket 绑定到本地地址,这样其他 socket 就可以通过 connect 连接它。

        (3)根据意愿,可以通过 listen() 接口来接收连接,并设置连接队列的上限值。

        从 Linux 2.2 后,TCP socket 的 backlog 参数就发生了变化,它表示的是已经建立连接等待接收(accept)的队列长度,而不是未完成连接的队列长度。未完成的连接队列长度的上限可以通过  /proc/sys/net/ipv4/tcp_max_syn_backlog 设置。当开启了同步 cookie 功能时,这个设置将被忽略,即没有本地最大长度限制。参考 tcp(7) 获得更多信息。

        如果 backlog 大于 /proc/sys/net/core/somaxconn,那么默认复制这个值到 somaxconn。Linux 5.4 以后,这个默认值为 4096,而在早期的版本中,默认值是 128。Linux 2.4.25 之前,这个值更是硬编码为 128,不可改变。

accept

accept()           遵循 POSIX.1 - 2008

accept4()         遵循 Linux

1.库

标准 c 库,libc, -lc

2.头文件

<sys/socket.h>

3.接口定义

       int accept(int sockfd, struct sockaddr *_Nullable restrict addr,
                  socklen_t *_Nullable restrict addrlen);

       int accept4(int sockfd, struct sockaddr *_Nullable restrict addr,
                  socklen_t *_Nullable restrict addrlen, int flags);

4.接口描述

       accept() 系统调用用作基于连接的 socket 上(SOCK_STREAM,SOCK_SEQPACKET)。它会从监听 socket(sockfd) 的等待连接队列里拿出第一个连接请求,然后创建一个新的连接了的 socket,并返回指向该 socket 的新的文件描述符。新创建的 socket 并不处于监听状态,原始 socket(sockfd) 不受该调用影响。

        sockfd 参数是一个通过 socket() 接口创建的 socket,通过 bind() 绑定到了本地地址上,使用 listen() 监听着它的连接情况。

        addr 参数是一个指向 sockaddr 结构的指针,这个结构由通信层填充的对端 socket 地址。返回的 addr 地址格式取决于具体的地址家族(可以参考 socket() 和相关协议 man 页面)。当 addr 是 NULL 时,不会向里填充任何东西。在这种情况下,addrlen 也没有用,也应该是  NULL。

        addrlen 参数是一个输入输出参数,调用者必须使用 addr 结构的大小来初始化它,并返回对端地址的实际大小。

        如果提供的 buffer 太小,那么返回的地址将会被截断。这种情况下,addrlen 会返回一个比提供值大的数值。

        如果当前队列上没有等待着的连接,并且 socket 没有被设置为非阻塞,那么 accept() 将会一直阻塞直到有连接到达。而如果 socket 被设置为非阻塞,那么 accept() 将会报告 EAGAIN 或者 EWOULDBLOCK 错误码。

        为了获得新到连接通知,我们可以使用 select()、poll()、epoll 接口。当有新连接尝试发生时,我们会收到可读的事件,然后我们可以调用 accept() 来获取对应连接的 socket。

        也可以设置当 socket 上有动静时发送 SIGIO 信号,参考 socket(7)。

        如果 flags 为 0,那么 accept4() 等同于 accept()。flags 可以是以下标志的位或:

        SOCK_NONBLOCK

        设置新文件描述符的文件状态标记为 O_NONBLOCK,这样就不用再调用 fcntl() 来实现同样的效果了。

        SOCK_CLOEXEC

        设置新文件描述符的 FD_CLOEXEC 标志,可以查看 open(2) 说明来看这个标志的意义。

5.返回值

        成功时,这个系统调用返回一个接收 socket 的文件描述符(非负整数)。

        发生错误时,返回 -1,并设置errno 来指示错误类型,addrlen 不会改变。

        Linux 的 accept() 以及 accept4() 接口会将既存的网络错误传递到新创建的 socket 上。这个行为和 BSD socket 实现是不一样的。为了实现可靠的操作,我们需要处理相应协议的网络错误,把它们当作 EAGAIN 重试处理。在 TCP/IP 的场景下,会有 ENETDOWN/EPROTO/ENOPROTOOPT/EHOSTDOWN/ENONET/EHOSTUNREACH/EOPNOTSUPP/ENETUNREACH 等网络错误。

        错误值定义如下:

EAGAIN/EWOULDBLOCK socket 设置为非阻塞,并且当前没有连接等待接收。POSIX.1-2001 和 POSIX.1-2008 都允许返回随便哪个错误码,并且并不要求这两个值相同,所以移植程序应该对每个都进行处理。
EBADF sockfd 不是一个打开的文件描述符
ECONNABORTED 连接已经终止
EFAULT addr 参数不是用户地址空间可写的地址
EINTR 系统调用在有效的连接到达前被信号打断
EINVAL socket 没有处在监听连接状态,或者 addrlen 不合法
EINVAL (accept4()) flags 的值不合法
EMFILE 文件描述符数达到进程最大限制
ENFILE 系统文件描述符数达到系统最大限制
ENOBUFS/ENOMEM 没有足够的内存。这通常说的不是系统内存,而是内存分配受到 socket 缓冲区限制而无法分配
ENOTSOCK sockfd 文件描述符不是一个 socket
EOPNOTSUPP socket 不是 SOCK_STREAM 类型
EPERM 防火墙规则禁止连接
EPROTO 协议错误

        此外,新 socket 协议的网络错误也会返回,Linux 内核还可能返回一些其他错误:ENOSR/ESOCKTNOSUPPORT/EPROTONOSUPPORT/ETIMEDOUT。ERESTARTSYS 也可能在 trace 过程中返回。

Linux 上,accept() 新返回的 socket 不会从监听 socket 上集成发文件状态标志,比如 O_NONBLOCK 和 O_ASYNC。这个行为和 BSD 实现是不一样。一个可移植的程序不应该对这些进行假设,显示的设置这些标志。

6.注意

       我们收到 SIGIO 信号后或者 select()/poll/epoll 返回一个可读事件后,并不一定真的有连接存在,因为很可能在 accept() 调用之前这个连接因为网络被异步网络错误或者其他线程移除。一旦这种情况发送,系统调用就会一直阻塞到下一个连接到达。为了保证 accept() 永不阻塞,sockfd 指定的 socket 必须设置 O_NONBLOCK 标志。

        对于有些需要显示确认的协议,比如 DECnet,accept() 只是将下一个连接请求从从队列里拿出来而不做确认。确认是通过对文件描述符 read 或者 write 完成。目前只有 DECnet 在 Linux 上有类似语义。

        socklen_t 类型

        在原始的 BSD 实现中,accept() 第三个参数被声明为 int *。POSIX.1g 草稿标准想将其改为 size_t *C,后来 POSIX 标准和 glibc 2.x 把它定义为 socklen_t *。

7.代码

       #include <stdio.h>
       #include <stdlib.h>
       #include <string.h>
       #include <sys/socket.h>
       #include <sys/un.h>
       #include <unistd.h>

       #define MY_SOCK_PATH "/somepath"
       #define LISTEN_BACKLOG 50

       #define handle_error(msg) \
           do { perror(msg); exit(EXIT_FAILURE); } while (0)

       int
       main(void)
       {
           int                 sfd, cfd;
           socklen_t           peer_addr_size;
           struct sockaddr_un  my_addr, peer_addr;

           sfd = socket(AF_UNIX, SOCK_STREAM, 0);
           if (sfd == -1)
               handle_error("socket");

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

           if (bind(sfd, (struct sockaddr *) &my_addr,
                    sizeof(my_addr)) == -1)
               handle_error("bind");

           if (listen(sfd, LISTEN_BACKLOG) == -1)
               handle_error("listen");

           /* Now we can accept incoming connections one
              at a time using accept(2). */

           peer_addr_size = sizeof(peer_addr);
           cfd = accept(sfd, (struct sockaddr *) &peer_addr,
                        &peer_addr_size);
           if (cfd == -1)
               handle_error("accept");

           /* Code to deal with incoming connection(s)... */

           if (close(sfd) == -1)
               handle_error("close");

           if (unlink(MY_SOCK_PATH) == -1)
               handle_error("unlink");
       }

下一篇 【计算机网络】网络编程接口 Socket API 解读(5)​​​​​​​文章来源地址https://www.toymoban.com/news/detail-709171.html

到了这里,关于【计算机网络】网络编程接口 Socket API 解读(4)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【计算机网络】网络编程接口 Socket API 解读(10)

             Socket 是网络协议栈暴露给编程人员的 API,相比复杂的计算机网络协议,API 对关键操作和配置数据进行了抽象,简化了程序编程。         本文讲述的 socket 内容源自 Linux man。本文主要对各 API 进行详细介绍,从而更好的理解 socket 编程。         这个是 RFC 7

    2024年02月08日
    浏览(54)
  • 【计算机网络】网络编程接口 Socket API 解读(11)

             Socket 是网络协议栈暴露给编程人员的 API,相比复杂的计算机网络协议,API 对关键操作和配置数据进行了抽象,简化了程序编程。         本文讲述的 socket 内容源自 Linux man。本文主要对各 API 进行详细介绍,从而更好的理解 socket 编程。 遵循 POSIX.1-2008      

    2024年02月08日
    浏览(45)
  • 【计算机网络】网络编程接口 Socket API 解读(9)

             Socket 是网络协议栈暴露给编程人员的 API,相比复杂的计算机网络协议,API 对关键操作和配置数据进行了抽象,简化了程序编程。         本文讲述的 socket 内容源自 Linux man。本文主要对各 API 进行详细介绍,从而更好的理解 socket 编程。 续  【计算机网络】网

    2024年02月08日
    浏览(49)
  • 【计算机网络】网络编程接口 Socket API 解读(1)

             Socket 是网络协议栈暴露给编程人员的 API,相比复杂的计算机网络协议,API 对关键操作和配置数据进行了抽象,简化了程序编程。         本文讲述的 socket 内容源自 Linux man。本文主要对各 API 进行详细介绍,从而更好的理解 socket 编程。 遵循 POSIX.1 - 2001、POS

    2024年02月09日
    浏览(44)
  • 【计算机网络】网络编程接口 Socket API 解读(3)

             Socket 是网络协议栈暴露给编程人员的 API,相比复杂的计算机网络协议,API 对关键操作和配置数据进行了抽象,简化了程序编程。         本文讲述的 socket 内容源自 Linux man。本文主要对各 API 进行详细介绍,从而更好的理解 socket 编程。 poll()           遵

    2024年02月09日
    浏览(49)
  • 计算机网络--网络编程(1)

    简单认识一下传输层中的UDP和TCP: TCP:有链接,可靠传输,面向字节流,全双工 UDP:无连接,不可靠传输,面向数据报,全双工 有链接类似于打电话,通了就是有链接。没通就一直在等待。 无连接类似于发短信,只管发,不管到。 可靠传输就是保证信息传输的可靠性。就

    2024年02月11日
    浏览(46)
  • 【计算机网络】4 Socket网络编程

    目录 写在前面的话 概览 环境 URL请求程序: 2. 系统时间查询 服务端 T_TCPServer.py代码 客户端 T_TCPClient.py代码 运行效果 3. 网络文件传输 服务端 TF_TCPServer.py代码 运行效果(后面加了远程功能,效果图暂时还在本地) 4. 网络聊天室 服务端 UDPServer.py代码 客户端 UDPClient.py代码 运

    2024年02月01日
    浏览(45)
  • 【计算机网络】网络编程套接字(一)

    目录 1.预备知识 1.1.理解源IP地址和目的IP地址 1.2.认识端口号 1.2.1.理解\\\"端口号\\\"和\\\"进程ID\\\" 1.2.2.理解源端口号和目的端口号 1.3.认识TCP/UDP协议 1.3.1.TCP协议 1.3.2.UDP协议 1.4.网络字节序 网络字节序和主机字节序的转换 2.socket编程接口 2.1.sockaddr结构 struct sockaddr_in 的具体结构: 2.

    2024年02月08日
    浏览(53)
  • 计算机网络---网络编程套接字(一)

    ✨ 计算机网络—网络编程套接字之UDP数据报套接字编程 作者介绍: 🎓作者:偷偷敲代码的青花瓷🐱‍🚀 👀作者的Gitee:代码仓库 📌系列文章推荐:计算机网络 ——网络原理之初识 ✨✨我和大家一样都是热爱编程✨,很高兴能在此和大家分享知识,希望在分享知识的同时,能和大

    2023年04月09日
    浏览(37)
  • 【计算机网络】网络编程套接字(二)

    简单TCP服务器实现 我们将会使用到的头文件放在 comm.h 文件中 创建套接字 创建过程和UDP服务器几乎完全一样,除了使用的是TCP服务器使用的是流式服务(SOCK_STREAM),UDP使用的是数据包服务(SOCK_DGRAM) 服务器绑定 绑定的过程和UDP服务器也是相同的,可以看着复习一下 定义好 st

    2024年02月13日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包