linux如何获取到达的udp数据包的目的地址问题

zhiys 2012-06-13 12:33:55
最近看 unix 网络编程:
主机环境:一台 udp server 存在多个ip ,如果udp socket 只是 bind 端口(假设1111口),则默认udp 程序会
榜定所有ip的1111 端口,所以任何udp (目的地址是此 server 的1111 端口)的数据包都会被udp server 接收。
要获取到达udp 数据包的目的地址,需要使用 IP_RECVDSTADDR 或 IP_RECVIF 套接口选项获取,
但linux 不支持此2个选项, unix 网络编程 提供的方式是 单独对每一个 ip和端口 建立一个 socket id
然后对多个 socket id 调用 select , 但这个方法感觉太笨拙了,特别是服务器榜定很多Ip 情况下。

求教:大牛们,是否知道 在linux 环境下,有没有什么其他更好的解决办法???
...全文
650 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq120848369 2012-06-13
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 的回复:]

至于你说如何获得一个socket的本地地址和远端地址,对于udp来说是没有远端地址可谈的,因为是无连接的。

但本地地址是一定可以获取的,只要已经发送过一次消息或者主动bind过,getsockname即可。

C/C++ code
NAME
getsockname - get socket name

SYNOPSIS
#include <sys/sock……
[/Quote]

其实再准确的说,udp socket也是可以绑定远端地址的, 使用connect即可,但对udp socket调用connect不会引发任何网络握手,只是本地限制该socket只能接受connect的地址发来的包而已,并且默认发包地址(比如用send发送udp包)就是你connect的地址。这些UNP上都有描述,manpage也可以看到相关说明。

If the socket sockfd is of type SOCK_DGRAM then addr is the address to which datagrams are sent by default, and the only address from which datagrams
are received. If the socket is of type SOCK_STREAM or SOCK_SEQPACKET, this call attempts to make a connection to the socket that is bound to the
address specified by addr.
qq120848369 2012-06-13
  • 打赏
  • 举报
回复
至于你说如何获得一个socket的本地地址和远端地址,对于udp来说是没有远端地址可谈的,因为是无连接的。

但本地地址是一定可以获取的,只要已经发送过一次消息或者主动bind过,getsockname即可。

NAME
getsockname - get socket name

SYNOPSIS
#include <sys/socket.h>

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

DESCRIPTION
getsockname() returns the current address to which the socket sockfd is bound, in the buffer pointed to by addr. The addrlen argument should be ini-
tialized to indicate the amount of space (in bytes) pointed to by addr. On return it contains the actual size of the socket address.

The returned address is truncated if the buffer provided is too small; in this case, addrlen will return a value greater than was supplied to the call.
qq120848369 2012-06-13
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]

udp并发必须多socket, 其实就是模拟tcp而已.
[/Quote]

一个监听udp socket, 自定义连接请求协议, 创建一个新的udp socket,向请求者发回应答, 请求者便可获得服务它的server端udp ip/port,接下来就与这个ip/port通信即可。
qq120848369 2012-06-13
  • 打赏
  • 举报
回复
udp并发必须多socket, 其实就是模拟tcp而已.
zhiys 2012-06-13
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 的回复:]
引用 3 楼 的回复:

至于你说如何获得一个socket的本地地址和远端地址,对于udp来说是没有远端地址可谈的,因为是无连接的。

但本地地址是一定可以获取的,只要已经发送过一次消息或者主动bind过,getsockname即可。

C/C++ code
NAME
getsockname - get socket name

SYNOPSIS
#include <sys/……
[/Quote]

非常感谢你的帮助,我举个例子来说明一下我求解的问题。假设服务器A 有本地ip:192.168.0.1 ,
服务器B 有: 172.24.1.1 和 172.24.1.2 , 172.24.1.3 一共3个本地ip 。服务器B 运行udp
服务器程序,运行方式是迭代。服务器B 运行的udp 程序 bind 的ip 是 0.0.0.0(INADDR_ANY)
端口是 1111. 这时服务器B 的udp 程序同时监听3个ip 的1111 端口。

假设服务器A 上运行udp 的client 端,并往服务器B 的172.24.1.1的1111 端口发送一个
数据包。服务器B的 recvmsg 函数接收的此数据包,却无法知道服务器A 的client端是使用
服务器B 的哪一个ip 地址作为目的地址发送的此数据包。

qq120848369 2012-06-13
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]

还有,发现楼主概念理解错了,端口是整个机器唯一的,不是每个IP都有0-65535.
[/Quote]

另外,没有主动bind过的socket除了内核会在你connect/第一次send(to)/sendmsg的时候帮你绑定一个端口外,它是没有固定IP的,每次都会根据路由表选择合适的出口临时bind。

如果你是主动bind在一个IP上的,那么很明显只有从这个IP网卡过来的请求会被接受,其他网卡的包根本不知晓。
再比如你是bind在IP:0上的,那么很明显所有的网卡过来的请求都会被接受,并且不同网卡过来的accept的请求对应的服务端IP都是不同的。


楼主要理解:子网,路由,临时端口绑定,这些基础概念,否则模模糊糊的也就照葫芦画瓢不懂网络拓扑很悲哀。
qq120848369 2012-06-13
  • 打赏
  • 举报
回复
还有,发现楼主概念理解错了,端口是整个机器唯一的,不是每个IP都有0-65535.

69,369

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧