建立TCP连接的各个系统调用

这篇具有很好参考价值的文章主要介绍了建立TCP连接的各个系统调用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

TCP 连接的过程图

建立TCP连接的各个系统调用,计算机网络,tcp/ip,网络协议,网络

服务器

socket() 函数

socket() 返回的 sockfd 是一个描述符。socket()对应于普通文件的打开操作。普通文件的打开操作返回一个文件描述字,而socket()用于创建一个socket描述符(socket descriptor),它唯一标识一个socket。这个socket描述字跟文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。

int  socket(int protofamily, int type, int protocol);//返回sockfd

socket()的三个参数分别为:

  • protofamily:即协议域,又称为协议族(family)。常用的协议族有,AF_INET(IPV4)、AF_INET6(IPV6)、AF_LOCAL (或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
  • type:指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等(socket的类型有哪些?)。
  • protocol:故名思意,就是指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。

调用socket()返回的socket描述字存在于协议族(address family,AF_XXX)空间中,但没有一个具体的地址。如果想要给它赋值一个地址,就必须调用bind()函数,否则当调用connect()、listen()时系统会自动随机分配一个端口。

bind()

bind()函数把一个地址族中的特定地址赋给socket()返回的socket。服务器一般是要主动绑定IP地址和端口号的,但是客户端一般是不需要的,因为客户端调用connect的时候,内核会自动分配一个端口号给它。

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

bind()函数的三个参数分别为:

  • sockfd:即socket描述字,它是通过socket()函数创建了,唯一标识一个socket。bind()函数就是将给这个描述字绑定一个名字。
  • addr:一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同。
  • addrlen:对应的是addr的长度。

listen()

作为一个服务器,在调用 socket()、bind() 之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。

int listen(int sockfd, int backlog);

listen() 的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。

调用该函数后,socket会主动从连接套接字变为监听套接字。

accept()

TCP服务器端依次调用socket()、bind()、listen()之后,就会监听指定的socket地址了。TCP客户端依次调用socket()、connect()之后就向TCP服务器发送了一个连接请求。TCP服务器监听到这个请求之后,就会调用accept()函数取接收请求,这样连接就建立好了。之后就可以开始网络I/O操作了,即类同于普通文件的读写I/O操作。

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //返回连接connect_fd

accept()函数的三个参数分别为:

  • sockfd:sockfd就是上面的监听套接字,这个套接字用来监听一个端口,当有一个客户与服务器连接时,它使用这个端口号,而此时这个端口号正与这个套接字关联。当然客户不知道套接字这些细节,它只知道一个地址和一个端口号。
  • addr:这是一个结果参数,它用来接受一个返回值,这返回值指定客户端的地址,当然这个地址是通过某个地址结构来描述的,用户应该知道这一个什么样的地址结构。如果对客户的地址不感兴趣,那么可以把这个值设置为NULL。
  • addrlen:它也是结果参数,用来接受上述addr的结构的大小的,它指明addr结构所占有的字节数大小。同样的,它也可以被设置为NULL。

如果accept成功返回,则服务器与客户已经正确建立连接了,此时服务器通过accept返回的套接字来完成与客户的通信。

accept()默认会阻塞进程,直到有一个客户连接建立后返回,它返回的是一个最新可用的套接字,这个套接字是连接套接字。

两种套接字
监听套接字: 监听套接字正如accept的参数sockfd,它是监听套接字,在调用listen函数之后,是服务器调用socket()函数生成的套接字,称为监听socket描述字(监听套接字)

连接套接字:调用listen()后,一个套接字会从主动连接的套接字变身为一个监听套接字;而accept()返回的是已连接socket描述字(一个连接套接字),它代表着一个网络已经存在的点对点连接。

一个服务器通常只创建一个监听套接字,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建了一个连接套接字,当服务器完成了对某个客户的服务,相应的连接套接字就被关闭。

**自然要问的是:为什么要有两种套接字?**原因很简单,如果使用一个描述字的话,那么它的功能太多,使得使用很不直观,同时在内核确实产生了一个这样的新的描述字。

连接套接字socketfd_new 并没有占用新的端口与客户端通信,依然使用的是与监听套接字socketfd一样的端口号。

read()、write()等

服务器与客户建立好连接后,就可以调用网络I/O进行读写操作了,网络I/O操作有下面几组:

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

read函数是负责从fd中读取内容.当读成功时,read返回实际所读的字节数,如果返回的值是0表示已经读到文件的结束了,小于0表示出现了错误。如果错误为 EINTR 说明读是由中断引起的,如果是 ECONNREST 表示网络连接出了问题。

write函数将buf中的nbytes字节内容写入文件描述符fd,成功返回写入的字节数。失败时返回 -1,并设置errno变量,如果错误为 EINTR 表示在写的时候出现了中断错误。如果为 EPIPE 表示网络连接出现了问题。

close()

在服务器与客户端建立连接之后,会进行一些读写操作,完成了读写操作就要关闭相应的socket描述字,好比操作完打开的文件要调用fclose关闭打开的文件。

int close(int fd);

close一个 TCP socket 的行为是把该socket标记为已关闭,然后立即返回到调用进程。该描述字不能再由调用进程使用,也就是说不能再作为read或write的第一个参数。

注意:close操作只是使相应socket描述字的引用计数-1,只有当引用计数为0的时候,才会触发TCP客户端向服务器发送终止连接请求。

客户端

socket()

客户端调用的socket()函数与服务器调用的socket()函数相同,区别在于客户端不用调用bind()为socket()返回的socket绑定一个地址。

connect()

客户端调用 connect() 发出连接请求。调用 connect() 时由系统随机生成一个端口号和自身的ip地址组合,并指定给socket。

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

connect函数的第一个参数即为客户端的socket描述字,第二参数为服务器的socket地址,第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接。

read()、write()等
参见上文。

close()函数
参见上文。

建立TCP连接时各个系统调用的返回时机
建立TCP连接的各个系统调用,计算机网络,tcp/ip,网络协议,网络

从图中可以看出:

  1. 当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时 connect 进入阻塞状态;
  2. 服务器监听到连接请求,即收到 SYN J 包,调用accept函数接收请求向客户端发送 SYN K ,ACK J+1,这时 accept 进入阻塞状态;
  3. 客户端收到服务器的 SYN K ,ACK J+1 之后,这时 connect 返回,并对SYN K进行确认;服务器收到 ACK K+1 时,accept返回,至此三次握手完毕,连接建立。

将套接字设置为非阻塞

  int x;
  x=fcntl(sockfd,F_GETFL,0);
  fcntl(sockfd,F_SETFL,x | O_NONBLOCK);

fcntl() 是对文件描述符进行操作的一个函数,F_GETFL表示获取属性,而F_SETFL表示设置属性文章来源地址https://www.toymoban.com/news/detail-605976.html

到了这里,关于建立TCP连接的各个系统调用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 计算机网络必会:TCP和UDP,面向连接,无连接,可靠与不可靠

    我在学习计算机网络的过程中,遇到了TCP和UDP解释,其中,无连接,面向连接,对我有很多新启发,下面就简单来聊聊,有兴趣多点个赞收藏一下,有错误可以私信反馈,欢迎打扰 TCP的主要特点: 1、TCP是面向连接的传输层协议。 2、每一条TCP连接只能有两个端点,TCP连接只

    2024年02月06日
    浏览(62)
  • C++11实现计算机网络中的TCP/IP连接(Windows端)

    TCP/IP 指 传输控制协议/网际协议(Transmission Control Protocol / Internet Protocol) 。 [1] 在TCP/IP协议簇中主要包含以下内容: TCP (传输控制协议) - 应用程序之间通信 UDP (用户数据报协议) - 应用程序之间的简单通信 IP (网际协议) - 计算机之间的通信 ICMP (因特网消息控制协议) - 针对错

    2024年02月02日
    浏览(44)
  • 计算机网络 运输层下 | TCP概述 可靠传输 流量控制 拥塞控制 连接管理

    TCP是面向连接的运输协议 每一条TCP只能有两个端点,点对点 提供可靠的全双工交付 面向字节流,但占用很多资源 不提供广播和多播服务 所以从某种意义来说 UDP是一种更加有效的工作方式 TCP面向流的概念 把字节写入发送缓冲,加上TCP首部构成TCP报文段,从接收缓存读取字

    2024年02月04日
    浏览(55)
  • 计算机网络:思科实验【8-运输层端口、TCP的运输连接管理、动态主机配置协议DHCP的作用】

    🌈个人主页:godspeed_lucip 🔥 系列专栏:Cisco Packet Tracer实验 本文对应的实验报告源文件请关注微信公众号 程序员刘同学 ,回复 思科 获取下载链接。 1 验证运输层 TCP / IP 端口号的作用 2 验证 TCP 使用三报文握手建立连接 3 验证 TCP 使用四报文挥手释放连接 Cisco Packet Tracer 模

    2024年03月13日
    浏览(72)
  • 【计算机网络】深入理解TCP协议二(连接管理机制、WAIT_TIME、滑动窗口、流量控制、拥塞控制)

    正常情况下,TCP需要经过三次握手建立连接+四次挥手断开链接,下面看一个图: 服务器的状态变化: [CLOSED - LISTEN] 服务器端调用listen后进入LISTEN状态, 等待客户端连接; [LISTEN - SYN_RCVD] 一旦监听到连接请求(同步报文段), 就将该连接放入内核等待队列中, 并向客户端发送SYN确认

    2024年02月07日
    浏览(60)
  • 计算机网络【IP数据包首部的各个字段详解】

    一个IP数据包的首部至少是20个字节! 版本: 就是指出IP数据包是什么版本;常见的版本就是 0100 IPV4 和 0110 IPV6 ; 首部长度: 整个IP数据包的首部长度,不包括数据部分; 但是首部长度只用4个bit存储,表示最大值也是1111,即15; 而我们实际上首部长度还需要乘于5才可以得到实

    2024年02月06日
    浏览(43)
  • TCP,TCP 连接建立,TCP 连接断开,Socket 编程

    目录 TCP基本认识 TCP 头格式有哪些? 为什么需要 TCP 协议? TCP 工作在哪一层? 什么是 TCP ? 什么是 TCP 连接? #如何唯一确定一个 TCP 连接呢? UDP 和 TCP 有什么区别呢?分别的应用场景是? #TCP 和 UDP 可以使用同一个端口吗? TCP 连接建立 #TCP 三次握手过程是怎样的? 为什么

    2023年04月27日
    浏览(51)
  • 建立和终止TCP连接过程

    http 和 https 区别: http 使用过程中存在安全性问题:http 使用明文通信,容易被窃听。由于 http 不验证通信方的身份,攻击者可以伪装成合法的通信方进行欺骗。并且 http 无法提供报文的完整性验证,因此报文有可能被篡改。 https 使用 SSL(Secure Sockets Layer) 或 TLS(Transport Layer

    2024年02月15日
    浏览(38)
  • TCP的连接建立与释放

        TCP是面向连接的协议,运输连接是用于传输TCP报文的。TCP运输的建立和释放是每一次面向连接的通信中必不可少的过程,同时也是在面试过程中必被提问的问题之一。      TCP运输连接有三个阶段,分别是:连接建立阶段、数据传输阶段、连接释放阶段。 一:TCP的连接

    2024年02月03日
    浏览(36)
  • SNMP 计算机网络管理 实验1(二) 练习与使用Wireshark抓取SNMP数据包抓包之 任务三分析并验证TCP三次握手建立连接时三次握手工作过程

    ⬜⬜⬜ 🐰🟧🟨🟩🟦🟪(*^▽^*)欢迎光临 🟧🟨🟩🟦🟪🐰⬜⬜⬜ ✏️write in front✏️ 📝个人主页:陈丹宇jmu 🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​ 🙉联系作者🙈by QQ:813942269🐧 🌈致亲爱的读者:很高兴你能看到我的文章,希望我的文章可以帮助到你,祝万事

    2024年02月12日
    浏览(58)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包