惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

有赞技术团队
有赞技术团队
Apple Machine Learning Research
Apple Machine Learning Research
IT之家
IT之家
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
B
Blog RSS Feed
酷 壳 – CoolShell
酷 壳 – CoolShell
人人都是产品经理
人人都是产品经理
Hugging Face - Blog
Hugging Face - Blog
博客园_首页
V
V2EX
aimingoo的专栏
aimingoo的专栏
爱范儿
爱范儿
博客园 - 聂微东
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Stack Overflow Blog
Stack Overflow Blog
罗磊的独立博客
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
MongoDB | Blog
MongoDB | Blog
Jina AI
Jina AI
T
The Blog of Author Tim Ferriss
月光博客
月光博客
云风的 BLOG
云风的 BLOG

博客园_首页

Linux实操--组管理、权限管理和定时任务 Java + EasyExcel 实现单个接口导出多个Excel Mem0 源码解析系列(二):提示词工程的深度剖析 Openclaw TaskFlow究竟是什么?和普通Skill技能有什么区别 博文阅读密码验证 - 博客园 嘉立创开源:应该是全网MicroPython教程最多的开发板 Hermes Agent 集成实践:从协议到生产 2026年AI编程工具横评:Cursor、Codex、Claude Code、Zed、Windsurf Java程序员必看的RAG入门教程 2026 AI效率神器:Superpowers + Claude Code 保姆级教程 本地大模型部署全攻略:从 0 到 1 玩转 Ollama 【从0到1构建一个ClaudeAgent】内存管理-上下文压缩 .NET 高级开发 | 设计、实现一个事件总线框架 电子小白入门之NE555 3. WorkBuddy:隐藏玩法,一键召唤专家,让 AI 以"专家身份"给你干活 和AI一起搞事情#3:Claude Teammate 游戏开发翻车实录 【OpenClaw】通过 Nanobot 源码学习架构---(7)Memory C# .NET 周刊|2026年3月3期 我在 Debian 11 上把 K8s 单机搭起来了,过程没你想的那么顺(/opt 目录版) 深度学习进阶(七)Data-efficient Image Transformer CLI+Skill搭建浏览器AI自动化框架,告别一切重复枯燥任务 告别Token账单无底洞:OpenClaw本地部署,重塑企业数据主权的唯一解 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! SBTI 爆火后,我做了个程序员版的 CBTI。。已开源 + 附开发过程 多模态检索开始进入工程期:用 Sentence Transformers 搭建可落地的 Multimodal RAG 100多行代码实现一个最简单的Agent(用ReAct) Claude Code 通关手册(八):推荐 5 个 Hooks,代码质量提升 3 倍 老板:“有人截图了!”。安全部门:“收到,马上查暗水印!” - why技术 技术之外,皆是人间 C#/.NET/.NET Core技术前沿周刊 | 第 69 期(2026年4.01-4.12)
【Azure Relay】记录使用Azure Relay在通信中遇见侦听器(List...
编码者卢布 · 2026-05-17 · via 博客园_首页

问题描述

使用Azure Relay服务,可以帮助服务器与客户端无法直接访问的情况下,提供牵线搭桥中转的沟通方式,俗称“中继”。

它是一种单对单的通信方式,需要对服务端和客户端代码有一些改动才可以,需要定义服务端侦听器(Listener)来接受消息,客户端(Caller)来发送消息。

  • 服务端侦听器(Listener): 使用 HybridConnectionListener 对象来初始化对象
  • 客户端发送者(Caller):使用 HybridConnectionClient 对象来初始化对象

image

Azure Relay的工作原理如下

原理图:

Processing of Incoming WCF Relay Requests

流程说明:

  1. Listening client sends a listening request to the Azure Relay service. The Azure load balancer routes the request to one of the gateway nodes.
  2. The Azure Relay service creates a relay in the gateway store.
  3. Sending client sends a request to connect to the listening service.
  4. The gateway that receives the request looks up for the relay in the gateway store.
  5. The gateway forwards the connection request to the right gateway mentioned in the gateway store.
  6. The gateway sends a request to the listening client for it to create a temporary channel to the gateway node that's closest to the sending client.
  7. The listening client creates a temporary channel to the gateway that's closest to the sending client. Now that the connection is established between clients via a gateway, the clients can exchange messages with each other.
  8. The gateway forwards any messages from the listening client to the sending client.
  9. The gateway forwards any messages from the sending client to the listening client.

基于以上的理解,当Listener 或 Caller 都突然中断的时候, Listener端会记录什么异常日志呢?Caller端会记录什么异常日志呢?

问题解答

第一部分:Caller端异常退出的情况, Listener会记录什么日志呢?

结果

在Listener的日志中,会输出如下的错误消息。

如果不对异常进行处理,会导致整个进程奔溃,Listener退出。

Exception in processing connection: 
Microsoft.Azure.Relay.RelayException: The remote party closed the WebSocket connection without completing the close handshake.
TrackingId:xxx-xx-xx-xx-xxxx4_G8_G9,
Address:sb://xxxxxxxx.servicebus.chinacloudapi.cn/xxxxxxxt01,
Timestamp:5/17/2026 8:48:56 AM

---> System.Net.WebSockets.WebSocketException: The remote party closed the WebSocket connection without completing the close handshake. at System.Net.WebSockets.WebSocketBase.WebSocketOperation.<Process>d__19.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Net.WebSockets.WebSocketBase.<ReceiveAsyncCore>d__45.MoveNext() --- End of stack trace from previous location where exception was thrown ---

实验

分别启动Listener 和 Caller,在正常通信两次后,直接关闭Caller窗口

image

第二部分:Listener端异常退出的情况, Caller会记录什么日志呢?

结果

在Caller的日志中,会输出如下的错误消息。

Microsoft.Azure.Relay.RelayException: 
The remote party closed the WebSocket connection without completing the close handshake.
TrackingId:xxxx-x-x-xx-xxxx5e79e2e,
Address:sb://xxxxxx.servicebus.chinacloudapi.cn/xxxxxxst01, Timestamp:5/17/2026 9:29:11 AM
---> System.Net.WebSockets.WebSocketException: The remote party closed the WebSocket connection without completing the close handshake. at System.Net.WebSockets.WebSocketBase.WebSocketOperation.<Process>d__19.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Net.WebSockets.WebSocketBase.<ReceiveAsyncCore>d__45.MoveNext()

实验

分别启动Listener 和 Caller,在正常通信后,直接关闭Listener窗口

image

对比两种情况下的日志,都是 Microsoft.Azure.Relay.RelayException: The remote party closed the WebSocket connection without completing the close handshake. 

微小的区别在异常消息中的TrackingId格式不同:

  • 如果是Caller异常断开,TrackingId中会携带 _GX_GX 标识,比如: TrackingId:xxx-xx-xx-xx-xxxx4_G8_G9 
  • 如果是Listener异常断开,TrackingId中不会携带,它的值就是普通的guid字符串,如TrackingId:xxx-xx-xx-xx-xxxxxx0a5

以上内容,供您参考。

参考资料

什么是 Azure 中继?https://docs.azure.cn/zh-cn/azure-relay/relay-what-is-it

开始在 .NET 中使用中继混合连接 WebSocket : https://docs.azure.cn/zh-cn/azure-relay/relay-hybrid-connections-dotnet-get-started