为了实现使用多播向网络中的其他进程发送小型周期性消息的网络应用程序,我在.Net框架中使用API有哪些选择?除了我明显的当前选择,System.net.sockets API,WCF是否提供了更简单的方法?或者WCF纯粹是基于SOA的点对点IPC机制?
注意:我非常熟悉多播编程的实现细节.我感兴趣的是.Net框架提供的其他选择.
我正在C#中编写UDP多播客户端/服务器对,我需要50-100μsec(微秒)的延迟来限制服务器传输速率.这有助于避免重大数据包丢失,还有助于防止磁盘I/O绑定的客户端过载.请不要建议Thread.Sleep或Thread.SpinWait.我不会问我是否需要其中任何一个.
我的第一个想法是使用某种高性能计数器,然后做一个简单的while()循环来检查已用时间,但我想避免这种情况,因为它感觉很笨拙.那不会也会占用服务器进程的CPU利用率吗?
跨平台解决方案的奖励积分,即不是Windows特定的.先谢谢你们!
我需要确定向我发送多播数据包的机器的IP,以便我可以通过单播响应它.
我正在使用以下csharp(.Net 3.5)代码通过多播连接接收数据包(为简洁起见,已编辑代码,并删除了错误检查和不相关的选项):
IPEndPoint LocalHostIPEnd = new IPEndPoint(IPAddress.Any, 8623);
Socket UDPSocket = new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);
UDPSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, 1);
UDPSocket.Bind(LocalHostIPEnd);
//Join the multicast group
UDPSocket.SetSocketOption(
SocketOptionLevel.IP,
SocketOptionName.AddMembership,
new MulticastOption(IPAddress.Parse("225.2.2.6")));
IPEndPoint LocalIPEndPoint = new IPEndPoint(IPAddress.Any ,Target_Port);
EndPoint LocalEndPoint = (EndPoint)LocalIPEndPoint;
// Create the state object.
StateObject state = new StateObject();
state.buffer.Initialize();
state.workSocket = UDPSocket;
state.id = "state0";
//Set up my callback
UDPSocket.BeginReceiveMessageFrom(
state.buffer,
0,
StateObject.BufferSize,
0,
ref LocalEndPoint,
new AsyncCallback(ReceiveCallback),
state);
Run Code Online (Sandbox Code Playgroud)
这是回调,我试图获取源IP:
private void ReceiveCallback( IAsyncResult ar )
{
IPEndPoint LocalIPEndPoint = new …Run Code Online (Sandbox Code Playgroud) 我在localhost上使用多播UDP来实现在一台机器上运行的松散的协作程序集合.以下代码适用于Mac OSX,Windows和Linux.缺点是代码也会在localhost网络之外接收UDP数据包.例如,sendSock.sendto(pkt, ('192.168.0.25', 1600))当我从我网络上的另一个盒子发送时,我的测试机器会收到它.
import platform, time, socket, select
addr = ("239.255.2.9", 1600)
sendSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sendSock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 24)
sendSock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF,
socket.inet_aton("127.0.0.1"))
recvSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
recvSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
if hasattr(socket, 'SO_REUSEPORT'):
recvSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, True)
recvSock.bind(("0.0.0.0", addr[1]))
status = recvSock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(addr[0]) + socket.inet_aton("127.0.0.1"));
while 1:
pkt = "Hello host: {1} time: {0}".format(time.ctime(), platform.node())
print "SEND to: {0} data: {1}".format(addr, pkt)
r = sendSock.sendto(pkt, addr)
while select.select([recvSock], [], [], 0)[0]:
data, fromAddr = recvSock.recvfrom(1024)
print …Run Code Online (Sandbox Code Playgroud) 是否可以在单个套接字上接收来自多个组播组的数据?
例如:
void AddGroup(int sock,
const char* mc_addr_str,
int mc_port,
const char* interface) {
struct sockaddr_in mc_addr;
memset(&mc_addr, 0, sizeof(mc_addr));
mc_addr.sin_family = AF_INET;
mc_addr.sin_addr.s_addr = inet_addr(mc_addr_str);
mc_addr.sin_port = htons(mc_port);
if ((bind(sock, (struct sockaddr *) &mc_addr,
sizeof(mc_addr))) < 0) {
perror("bind() failed");
exit(1);
}
// construct an IGMP join request structure
struct ip_mreq mc_req;
mc_req.imr_multiaddr.s_addr = inet_addr(mc_addr_str);
mc_req.imr_interface.s_addr = inet_addr(interface);
if ((setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(void*) &mc_req, sizeof(mc_req))) < 0) {
perror("setsockopt() failed");
exit(1);
}
}
Run Code Online (Sandbox Code Playgroud)
添加一个组播组时,此代码有效.但是当我尝试添加另一个时,"绑定"失败了.我不太明白为什么绑定首先需要在那里?(但没有它,代码不起作用).
理想情况下,我想在同一个套接字上多次调用AddGroup.这可能吗?或者我每组需要一个插槽然后只使用轮询?
我试图了解多播如何在MSMQ中工作,但我甚至无法接收消息,即使是在同一台机器上也是如此.我显然做错了什么但看不清楚是什么.
这是我在的地方:
我手动创建了一个非事务性专用队列MulticastTest,然后将多播地址设置为234.1.1.1:8001.然后我的测试发送应用程序这样做:
MessageQueue queue = new MessageQueue("FormatName:MULTICAST=234.1.1.1:8001");
queue.Send("Hello World");
Run Code Online (Sandbox Code Playgroud)
这工作,它至少似乎发送我在同一台机器上的传出队列中看到的消息.至少我认为这是正确的,如果不是,请告诉我.
所以现在我尝试运行我的接收应用程序(在同一台机器上或配置为相同多播地址的不同机器上),我无法让它工作.如果我试试这个:
MessageQueue queue = new MessageQueue("FormatName:MULTICAST=234.1.1.1:8001");
var message = queue.Receive();
Run Code Online (Sandbox Code Playgroud)
它根本不起作用,该Receive()方法抛出异常说:
指定的格式名称不支持请求的操作.例如,无法删除直接队列格式名称
如果我尝试设置接收队列,因为.\private$\MulticastTest它至少等待消息但没有任何反应,所有消息仍然保留在传出队列中.
那么我做错了什么?是否需要运行某种服务以便MSMQ从传出队列发送消息?
我也试过根据这个问题向ANONYMOUS USER提供完全权限,但这没有任何影响.
如何获得底层syscall.Handle的*net.UDPConnWindows上?我想要这个句柄来设置IP_MULTICAST_TTL通道syscall.SetsockoptInt.在Linux上我执行以下操作:
func setTTL(conn *net.UDPConn, ttl int) error {
f, err := conn.File()
if err != nil {
return err
}
defer f.Close()
fd := int(f.Fd())
return syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_MULTICAST_TTL, ttl)
}
Run Code Online (Sandbox Code Playgroud)
但在Windows上,隐dup内*net.UDPConn的File()失败:
04:24:49 main.go:150:dup:不支持windows
并在源代码中标记为待办事项.我怎么能得到这个句柄?是否还有其他方法可以设置TTL?
我已将缺点提交给Go问题跟踪器:
我在网络上有一个设备通过UDP组播一个非常小的文件.我正在开发的iOS应用程序负责读取这些数据包,我选择使用GCDAsyncUdpSocket来执行此操作.该文件每半秒发送一次,但我几乎没有经常收到它(大约每3-10秒接收一次).
认为这可能是设备的问题,我开始使用Wireshark监控流量.这似乎反映了我在我的应用程序中看到的内容,直到我在Wireshark中启用"监控模式",此时每个UDP数据包都被捕获.此外,iOS模拟器开始接收所有丢失的数据包,因为它与我正在开发的Mac共享NIC.
有没有办法在iOS设备上启用"监控模式"或者我缺少哪些可以让丢失的数据包进入?我还看到GCDAsyncUdpSocket中有一个readStream方法.也许我需要使用它而不是beginReceiving?虽然如果是这样的话,我不知道如何在Objective-C中设置流.
这是我现在的测试代码:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSLog(@"View Loaded");
[self setupSocket];
}
- (void)setupSocket
{
udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *error = nil;
if (![udpSocket bindToPort:5555 error:&error])
{
NSLog(@"Error binding to port: %@", error);
return;
}
if(![udpSocket joinMulticastGroup:@"226.1.1.1" error:&error]){
NSLog(@"Error connecting to multicast group: %@", error);
return;
}
if (![udpSocket beginReceiving:&error])
{
NSLog(@"Error receiving: %@", error);
return;
}
NSLog(@"Socket Ready");
} …Run Code Online (Sandbox Code Playgroud) 我可能对绑定这个术语有一个基本的误解,但我对MulticastSocket及其构造函数的使用感到困惑.他们不会做我理解他们应该做的事应该这样做,任何能帮助我清除我的误解的人都会受到赞赏.
首先是我想要实现的目标.我试图编写一个简短的程序,创建一个MulticastSocket绑定它(即监听)在特定的网络适配器上,然后加入一个特定的多播组.我已经尝试了以下(客户端)代码,该代码工作正常,我可以在没有多播套接字超时的情况下组播数据包.
public class Main {
public static final int DEFAULT_MULTICAST_PORT = 5555;
public static final String multicastGroup = "225.4.5.6";
public static final String adapterName = "eth0";
public static final int MAX_PACKET_SIZE = 65507;
CharBuffer charBuffer = null;
Charset charset = Charset.defaultCharset();
CharsetDecoder decoder = charset.newDecoder();
static ByteBuffer message = ByteBuffer.allocateDirect(MAX_PACKET_SIZE);
static boolean loop = true;
static byte[] buffer = new byte[MAX_PACKET_SIZE];
public static void main(String[] args) {
try {
//MulticastSocket mSocket …Run Code Online (Sandbox Code Playgroud) 因此,在阅读了一些文档并从这里获得了很多帮助后,我终于实现了一个动态选择端点的收件人列表(动态收件人列表):
在我的代码中,MainApp_A每10秒生成一次报告,我希望它能够同时将报告发送到所有服务器,而不是逐个发送.因此,我开发了以下路线.
MainApp_A
main.addRouteBuilder(new RouteBuilder(){
@Override
public void configure() throws Exception {
from("direct:start").multicast().parallelProcessing()
.beanRef("recipientListBean", "route").end()
.log("${body}");
}
});
Run Code Online (Sandbox Code Playgroud)
RecipientListBean
@RecipientList
public Set<String> route(String body) {
return servers; //returns a collection of several severs
}
Run Code Online (Sandbox Code Playgroud)
我还检查了多播模式和动态路由的文档:
现在我有几个问题,我很困惑.所以我有几个问题: