udp中的connect()&bind()

2023-05-16

connect()&bind()的作用

udp

udp connect()

 #include <sys/types.h>         
 #include <sys/socket.h>
 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

udp connect()描述

  1. connect系统调用将sockfd关联的套接字连接到addr指定的地址,如果sockfd是SOCK_DGRAM类型的,那么这个地址就是唯一数据报发送和接收地址
  2. 有链接的协议一般只能成功connect()一次,而无连接的协议可以多次connect()来改变sockfd与addr的联系

返回值

  1. 0,返回成功
  2. EACCES ,EPERM 用户试图链接到一个广播地址,但是相应的socket broadcast flag没有设置,或者是因为有本地防火墙
  3. EADDRINUSE 地址已经被使用
  4. EAFNOSUPPORT 传参的地址中的address family 与sa_family不匹配
  5. EBADF 文件描述符sockfd非法
  6. EINTR connect被signal中断

udp connect()特殊的一些地方

经试验发现,若发送端(客户端)不调用connect(),则发送异步错误时,进程很难知道发送了什么。若是调用connect(),其实际作用也与tcp中有较大不同。

  1. 调用connect()不会发包,内核只是检查是否有立即可知的错误,记录对端的ip&port,于是立即返回。但是这样一个socket就只能与一个ip进行交互(此处包括广播ip)
  2. connect()后,异步错误会被返回,在write()到一个不可达的进程时,对方将发送icmp,我方udp收到这个报文,并在下次准备read()这个套接字时,返回connection refused
  3. 一般而言,无连接的udp在发送数据时,内核中也是会做链接操作的,等数据发送完毕然后断开连接。这样其实效率较低,若是发送进程明确知道自己将于某个进程长时间通信,可以调用connect()来提高效率。【Partridge和Pink 1993】指出,临时链接的UDP套接字会耗费每个UDP传输1/3的开销

广播/多播(组播)

什么是多播

组播通过把224.0.0.0-239.255.255.255的D类地址作为目的地址,有一台源主机发出目的地址是以上范围组播地址的报文,在网络中,如果有其他主机对于这个组的报文有兴趣的,可以申请加入这个组,并可以接受这个组,而其他不是这个组的成员是无法接受到这个组的报文的。

局域网内多播时发生了什么

若局域网中有一个接收进程启动,并通过setsockopt()加入到某多播组。ipv4层内部会保存以上信息,并告知数据链路层接收特定目的地址以太网帧(通过组播ip到以太网地址的映射)。但是接口卡做的是不完备过滤,即接口卡也可能会接收目的地址为其他地址的以太网帧。但是ip层是完备的,它会比较目的ip。

有了以上内容,我们就知道若是某个组播成员(假设是A机)进程关闭了接收,或者他根本就没加入过组播。那么当发送进程再次发生组播时,A机实际上会忽略这个组播数据,既然忽略了,也不会发送icmp了。若是这个A机上有多个进程都加入了这个多播组,那单个套接字成员关系上的抹除,不影响A机继续作为该多播组的成员,直到最后一个套接字也离开该多播组。这种情况下调用connect,应该是connect到一个组播地址。

如何加入到组播

int setsockopt(int sockfd,int level,int optname,void* optval,socklen_t optlen)

optnamedataTypefunction
IP_ADD_MEMBERSHIPstruct ip_mreqenter a group
IP_ADD_SOURCE_MEMBERSHIPstruct ip_mreq_sourceenter a SSM
IP_BLOCK_SOURCEstruct ip_mreq_sourceblock a source

以源特定组播为例

  1. 假设组播IP是GROUP

  2. 按惯例,建立socket,填充好port,sin_family.

  3. inet_aton(GROUP,&serv.sin_addr);
    inet_aton(GROUP,&mreq.imr_multiaddr);
    inet_aton(yourInterfaceIP,&(mreq.imr_interface));
    inet_aton(sourceIP,&(mreq.imr_sourceaddr));
    setsockopt(sockfd,SOL_IP,IP_ADD_SOURCE_MEMBERSHIP,&mreq,sizeof(mreq))
  4. 第一条语句的意思是接收进程的地址要设置成组播IP,第二至第四条语句的意思是要填充一个 struct ip_mreq_source结构。这个结构三个成员,分别是组播地址,本机一个接口的IP,以及多播发送方的IP

  5. setsockopt第三个参数指明这是加入源特定组播,第四个是上面说的结构体指针,第五个是它的长度

  6. 当optname是IP_ADD_MEMBERSHIP时,填充struct ip_mreq,这个结构体没有imr_sourceaddr成员

connect到多播ip的一个事实

UNP1上说可以connect到一个多播ip,我在把cli发送进程做了这样的设置。但是令人奇怪的是,我的发送程序再也收不到来自接收ser的任何信息。后来仔细翻UNP,发现上面说“目的地为为这个已连接UDP套接字的本地协议地址,发源地却不是该套接字早先connect到的协议地址的数据报,不会投递到该套接字,这样就限制了已连接套接字能且仅能与一个对端交换数据”。这个事实印证了这个说法。udp调用connect()需要付出这样的代价。

bind()以及REUSE_ADDR、REUSE_PORT功能

见下,非常详细

http://blog.csdn.net/yaokai_assultmaster/article/details/68951150

有待解决

此次试验在一台机子上进行,多播试验,发送端未做特殊设置,接收端设置IP_ADD_MEMBERSHIP。一开始观察到发送进程未bind()时,接收可以收到数据,但是却显示源地址是0.0.0.0。后发送端加上bind(),接收端依旧显示源地址是0.0.0.0。

后改变接收端设置,变为IP_ADD_SOURCE_MEMBERSHIP,并填上多播的源地址192.168.1.136。此时再测试,发现接收端依旧显示源地址是0.0.0.0。后发现当第二次启动发送端程序发送多播时,接收端显示源地址是192.168.1.136。于是我修改发送端程序,让他不再recv 接收端的回复,而是只发送数据。我发现第一次发生数据时,接收端总是不能得到发送端的源地址,但是第二次发送数据后,接收端就能知道源地址了。

TCP

三路握手

  1. tcp的稳定连接靠的是三路握手,而三路握手由connect(),accept()完成
  2. 服务器必须准备好接受外来的连接,这通常通过调用socket,bind,listen来完成
  3. 客户通过调用connect发起主动连接,这导致客户发送一个syn分节,它告诉服务器客户将发送的数据的初始序列号。
  4. 服务器则必须确认这个SYN,并发送ACK,同时自己也要发送一个SYN,这个SYn含有服务器发送数据的初始序列号,当这个ACK/SYN到达客户端时,connect()返回
  5. 客户发送对服务器发来的SYN的ACK,服务器收到这个ack后即从accept返回
  6. 三路握手完成

TCP连接终止

  1. TCP终止一个链接需要4个分节,因为终止是双边的,每一边两个分节,也就是说TCP可以存在半关闭状态
  2. 某进程先调用close(),他是主动关闭方,它将发送一个fin分节,这仅仅表示这个进程告诉对方他的数据已经发送完毕,不代表这个进程不能继续收数据
  3. 若另外一边也认为他的数据发送完毕,则也会调用close()发送fin分节
  4. 每个fin分节都需要被ACK

TIME_WAIT

  1. TIME_WAIT是主动执行关闭的那端的最后一个网络状态。停留在这个状态的时间是2MSL
  2. 这个状态存在有两个必要的理由,可靠的实现全双工连接的终止,让老的分组在网络中消逝
  3. 对于第一个理由,假设主动发起关闭的那端在收到被动关闭端来的fin后,发送对这个fin的ACK,然而这个ACK丢失了。则被动关闭方会重传一个FIN,这时,若是没有TIME_WAIT状态,主动关闭方在发完最后一个ACK后就不再维护状态信息,则此时被动关闭方重发的FIN到达,则主动关闭方将对这个FIN分节回应一个RST,这将被被动关闭方解释为一个错误。
  4. 对于第二个理由,若是一个链接终止后,但是网络上还有这个链接没有到达的分组,此时若是快速的启动一个新的链接,他的ip和port都和旧的一样,那万一这个旧的分组在此时到达,则会被新的连接误收。所以为了让旧的分组消逝,有必要等待一个较长的时间。

bind()

如果SO_REUSEADDR选项没有被设置,处于TIME_WAIT阶段的socket任然被认为是绑定在原来那个地址和端口上的。直到该socket被完全关闭之前(结束TIME_WAIT阶段),任何其他企图将一个新socket绑定该该地址端口对的操作都无法成功。这一等待的过程可能和延迟等待的时间一样长。所以我们并不能马上将一个新的socket绑定到一个刚刚被关闭的socket对应的地址端口对上。在大多数情况下这种操作都会失败。

然而,如果我们在新的socket上设置了SO_REUSEADDR选项,如果此时有另一个socket绑定在当前的地址端口对且处于TIME_WAIT阶段,那么这个已存在的绑定关系将会被忽略。事实上处于TIME_WAIT阶段的socket已经是半关闭的状态,将一个新的socket绑定在这个地址端口对上不会有任何问题。这样的话原来绑定在这个端口上的socket一般不会对新的socket产生影响。但需要注意的是,在某些时候,将一个新的socket绑定在一个处于TIME_WAIT阶段但仍在工作的socket所对应的地址端口对会产生一些我们并不想要的,无法预料的负面影响。但这个问题超过了本文的讨论范围。而且幸运的是这些负面影响在实践中很少见到。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

udp中的connect()&bind() 的相关文章

  • 在 Windows 7 上找不到模块“连接”

    请看下面 C Program Files nodejs gt npm g install connect npm http GET https registry npmjs org connect npm http GET https re
  • 在 Flask-SQLAlchemy 中的同一类中使用不同的绑定

    我目前有多个具有相同表和列 但内部数据不同 的数据库 很明显 我需要使用绑定来访问所有这些 但这显然不像这样做那么简单 class WhateverTable db Model tablename whatevertable whateve
  • 如何在QT中发送和接收UDP数据包

    我正在 QT 中编写一个小型应用程序 它通过本地网络发送广播 UDP 数据包 并等待来自网络上的一个或多个设备的 UDP 响应数据包 创建套接字并发送广播数据包 udpSocketSend new QUdpSocket this udpSo
  • 什么是消息边界?

    什么是 消息边界 在以下情况下 TCP 和 UDP 之间的区别之一是 UDP 保留消息 边界 我理解之间的区别TCP and UDP 但我不确定的定义 消息边界 由于 UDP 在每个单独的数据包中包含目的地和端口信息 因此是否可以为消息提供
  • php 将变量绑定到旧 PHP 中的函数作用域

    我想将变量绑定到函数的作用域 我可以在 PHP 5 3 之后使用 use 关键字在 php 中执行此操作 但是如何在 PHP 5 3 以下的版本中执行等效操作 test use keyword function test use keywo
  • 互联网上的 UDP 多播?

    我不确定如何最好地解决我的问题 我有一个在远程计算机上运行的服务 用于接收和处理 UDP 数据包 我希望该服务能够将这些数据包重新发送给任何需要它们的人 可能是任何人 通常是一台机器 但也可能更多 我认为 UDP 多播将是理想的 该服务可以
  • C++ UDP Socket端口复用

    如何在 C 中创建客户端 UDP 套接字 以便它可以侦听另一个应用程序正在侦听的端口 换句话说 如何在 C 中应用端口复用 我只想监听一个端口 您可以使用嗅探器来做到这一点 只需忽略来自不同端口的数据包即可 我可能需要阻止它发送一些特定的数
  • 对等网络应用程序的网络发现

    我希望有两个类 一个服务器类和一个客户端类 服务器类应该接收每个新客户端的 IP 地址和端口号并将它们存储在列表中 它应该为每个客户端提供已连接客户端及其 IP 地址的列表 然后 客户端可以使用 TCP 连接相互通信 问题是客户端不知道服务
  • 创建可以传递参数而无需创建新组件的函数

    我的问题与这个问题有关React用于渲染函数中的绑定函数 以下不是好的做法 render div 因为每次重新渲染都会向页面添加一个新功能 最终导致浏览器内存不足 解决方案是这样做 constructor this callFunction
  • 为什么我们可以将 sockaddr 转换为 sockaddr_in

    我明白为什么强制转换很有用sockaddr to sockaddr in 但我不明白这怎么可能 据我所知 它们的大小相同sockaddr in添加了sin zero使其大小相同 我想知道编译器如何知道从哪里获取信息sockaddr in如果
  • 使用 jQuery 将播放/暂停/结束功能绑定到 HTML5 视频

    我正在尝试绑定play pause and ended使用 jQuery 的事件但有一个问题 当我右键单击视频并选择播放或暂停时 图标会正确更改 当我单击播放按钮时 它会更改为暂停 但如果我单击暂停按钮继续播放视频 它不会更改为再次播放 谁
  • Rails 是否支持侦听 UDP 套接字的简洁方式?

    在 Rails 中 集成更新模型某些元素的 UDP 侦听过程的最佳方式是什么 特别是向其中一个表添加行 简单的答案似乎是在同一进程中使用 UDP 套接字对象启动一个线程 但不清楚我应该在哪里执行适合 Rails 方式的操作 有没有一种巧妙的
  • 为什么 SNMP 通常在 UDP 上运行而不是 TCP/IP 上?

    今天早上 工作中出现了大问题 因为 SNMP 陷阱没有 通过 因为 SNMP 是通过 UDP 运行的 我记得在大学网络课上 UDP 不能像 TCP IP 那样保证传输 维基百科说 SNMP 可以在 TCP IP 上运行 但 UDP 更常见
  • 检测用户在 jQuery 中向下滚动或向上滚动[重复]

    这个问题在这里已经有答案了 可能的重复 jquery 中向上 向下滚动的区别 https stackoverflow com questions 4989632 differentiate between scroll up down in
  • 在 jQuery 中绑定元素及其子元素

    我想将事件绑定到元素及其子元素 做这个的最好方式是什么 element bind click function event doSomething element bind click function event doSomething
  • C# 套接字数据报溢出

    我是 C 新手 我有一个关于udp套接字的小问题 我有一个聊天服务器 它接收特定结构的数据包 udp 数据报 为什么程序在套接字缓冲区已满时才接收数据 难道以后的一切就不应该失去吗 也许会出现数据包碎片 数据包结构 udp headers
  • boost 是否有可移植的方式来使用 ntohl/htonl/ntohs/htons 类型函数?

    我正在使用 UDP 特别是 boost asio ip udp socket 套接字 如果有帮助的话 头文件是什么 我需要哪些标头 类来处理 UDP 提升下的网络字节排序 刚刚发现就足够了 include
  • 从 Docker 容器发送多播数据包(到多播组)

    我有一个通过 UDP 多播发送消息的应用程序 我一直试图将其放在 docker 下 我在尝试从 Docker 容器发送多播数据包时遇到了很大的阻力 我已经能够通过 net host运行 docker 容器的选项 然而 我想坚持使用桥接配置
  • RTSP 设置后接收 RTP 数据包

    我正在尝试使用 Python 从 IP 摄像机流式传输 RTP 数据包 我能够使用 RTSP 协议发送描述 设置和播放命令 但是 我无法开始使用 RTP 传输实际视频流 这是代码 import socket def printrec rec
  • 向现有 TCP 和 UDP 代码添加 SSL 支持?

    这是我的问题 现在我有一个 Linux 服务器应用程序 使用 C gcc 编写 它与 Windows C 客户端应用程序 Visual Studio 9 Qt 4 5 进行通信 是什么very在不完全破坏现有协议的情况下向双方添加 SSL

随机推荐