一个S2S通信中的同步、异步问题的解决

最近在搞Openfire S2S时遇到了一个数据通信时的同步与异步问题。具体描述如下:

OF中的基本通信结构如下:

客户端与服务器的通信是同步的,服务器与服务器之间的通信却是异步的:客户端发送一个请求后就会阻塞一段时间,等待服务器的响应;服务器之间则采用消息通知的方式异步交流数据。

所以会出现下面这种情况:

客户端发送消息给服务器A,消息经入口路由到相应的功能模块进行处理,而此时需要从B服务器中获取一些额外的数据,比如验证发送上来的账号是否在另外的服务器有注册。一般情况下数据在本地的话就直接查找处理再给用户返回就行,但在其它服务器时直接返回就会出现结果错误或不完整,不返回则造成客户端超时。

处理这种情况的方法就是:接收到客户端的请求后,服务器A发送消息给B查询数据,同时将客户端的请求阻塞一个小的时间段(保证客户端不超时),等B返回数据后再继续执行下面的逻辑。(看了OF代码才明白了)

以查询是否为注册用户为例,OF是如下实现的:

UserManager.java public boolean isRegisteredUser(JID user) { XMPPServer server = XMPPServer.getInstance(); if (server.isLocal(user)) { //要查找的域为本地...... } else { //先按全JID的形式查找本地cache Boolean isRegistered = remoteUsersCache.get(user.toString()); if (isRegistered == null) { // Check if the bare JID of the user is cached isRegistered = remoteUsersCache.get(user.toBareJID()); if (isRegistered == null) { // 本地cache没有的情况下发送IQ消息去查询,接收方为对应的用户,这个接收方改为其它服务器就成了S2S了。 IQ iq = new IQ(IQ.Type.get); iq.setFrom(server.getServerInfo().getXMPPDomain()); iq.setTo(user.toBareJID()); iq.setChildElement("query", "http://jabber.org/protocol/disco#info"); // Send the disco#info request to the remote server. The reply will be // processed by the IQResultListener (interface that this class implements) //注册一个接受处理结果消息的Listener server.getIQRouter().addIQResultListener(iq.getID(), this); //这里进行了阻塞等待一段时间,等待对端的回应将结果放到cache中 synchronized (user.toBareJID().intern()) { server.getIQRouter().route(iq); // Wait for the reply to be processed. Time out in 1 minute. try { user.toBareJID().intern().wait(60000); } catch (InterruptedException e) { // Do nothing } } // 再去cache中查找结果 isRegistered = remoteUsersCache.get(user.toBareJID()); if (isRegistered == null) { // Disco failed for some reason (i.e. we timed out before getting a result) // so assume that user is not anonymous and cache result isRegistered = Boolean.FALSE; remoteUsersCache.put(user.toString(), isRegistered); } } } return isRegistered; } //处理接收查询结果消息,将结果放入cache public void receivedAnswer(IQ packet) { JID from = packet.getFrom(); // Assume that the user is not a registered user Boolean isRegistered = Boolean.FALSE; // Analyze the disco result packet if (IQ.Type.result == packet.getType()) { Element child = packet.getChildElement(); if (child != null) { for (Iterator it=child.elementIterator("identity"); it.hasNext();) { Element identity = (Element) it.next(); String accountType = identity.attributeValue("type"); if ("registered".equals(accountType) || "admin".equals(accountType)) { isRegistered = Boolean.TRUE; break; } } } } // Update cache of remote registered users remoteUsersCache.put(from.toBareJID(), isRegistered); // Wake up waiting thread synchronized (from.toBareJID().intern()) { from.toBareJID().intern().notifyAll(); } }

 

 

再来看看外层路由是如何捕获查询结果消息,并交给相应的业务逻辑处理的:

IQRouter.java private void handle(IQ packet) { ...... if (packet.getID() != null && (IQ.Type.result == packet.getType() || IQ.Type.error == packet.getType())) { // The server got an answer to an IQ packet that was sent from the server IQResultListener iqResultListener = resultListeners.remove(packet.getID()); if (iqResultListener != null) { resultTimeout.remove(packet.getID()); if (iqResultListener != null) { try { iqResultListener.receivedAnswer(packet); } catch (Exception e) { Log.error("Error processing answer of remote entity", e); } return; } } } } ......


结合上面的那段代码,就可以看出OF中是如何实现这个功能的了。

 

但这种做法的缺点也是很明显的:

1.需要原进程阻塞一个固定时间

2.需要每个涉及到同步、异步问题的地方都有一个接收结果的机制

所以可以针对以上两点做些改进。

 

05-07
<think>好的,我现在需要处理用户关于“S2S”(Server-to-Server)的查询。用户可能是在寻找S2S的定义、架构或实现相关的信息。首先,我应该明确S2S在IT领域的常见含义。 根据以往的知识,S2S通常指服务器到服务器的通信,涉及不同服务器之间的数据交换,常见于API集成、数据同步等场景。接下来,我需要确认用户的具体需求,但用户的问题已经明确指出需要了解架构、实现或定义,因此需要覆盖这三个方面。 首先,定义部分:S2S指服务器间直接通信,无需客户端介入。应用场景包括支付处理(如支付网关与银行服务器)、单点登录(如不同服务间的认证)、微服务通信等。这里需要确保定义准确,可能参考现有资料,但用户提供的引用似乎不相关,需要忽略。 架构方面,需要描述S2S的常见架构模式,比如基于REST API、消息队列或RPC。每种架构的优缺点和应用场景需要简要说明,例如REST适合HTTP通信,消息队列适合异步处理,而RPC适合低延迟需求。 实现部分,可以给出一个简单的代码示例,比如使用Python的requests库进行HTTP通信,或者使用gRPC的示例。需要注意代码的正确性和简洁性,符合用户示例中的Python代码风格。 相关问题部分,需要生成与S2S相关的问题,如安全性、认证机制、性能优化等,确保问题覆盖用户可能感兴趣的扩展内容。 同时,用户提到引用内容关于SDF和ResNet,但这些可能与当前问题无关,因此可以忽略。需要确保回答结构清晰,分点说明,并符合中文回答的要求。最后检查LaTeX格式是否正确,行内公式使用$...$,独立公式用$$...$$,但当前回答中可能不需要数学公式,所以可能不需要处理这部分。 总结步骤:定义S2S,架构类型,实现示例,应用场景,相关问题。确保每个部分简洁明了,帮助用户全面理解S2S的相关内容。</think>### Server-to-Server (S2S) 架构与实现 #### 定义 **Server-to-Server (S2S)** 指两个或多个服务器之间直接通信的技术模式,无需客户端(如浏览器或移动设备)作为中介。其核心目标是实现高效、安全的数据传输与业务逻辑协调,常见于分布式系统、微服务架构、API集成等场景[^1]。 #### 典型应用场景 1. **支付系统集成** 例如,电商平台服务器与第三方支付网关(如支付宝、PayPal)直接交互完成交易验证。 2. **单点登录(SSO)** 不同服务提供商的服务器通过令牌交换实现用户身份认证。 3. **数据同步与备份** 跨数据中心或云服务的数据库同步。 4. **微服务通信** 微服务间通过 REST API 或 RPC 调用实现功能协作。 #### 架构模式 1. **基于 REST API** - 使用 HTTP/HTTPS 协议,通过标准方法(GET/POST/PUT/DELETE)交换 JSON/XML 数据。 - 示例代码(Python): ```python import requests response = requests.post("https://api.example.com/data", json={"key": "value"}, headers={"Authorization": "Bearer token"}) ``` 2. **基于消息队列** - 使用 RabbitMQ、Kafka 等中间件实现异步通信。 - 特点:解耦、高吞吐,适用于事件驱动架构。 3. **基于 RPC(远程过程调用)** - 使用 gRPC 或 Thrift 框架,支持高效二进制协议。 - 示例(gRPC 协议定义): ```protobuf service DataService { rpc SendData (DataRequest) returns (DataResponse); } ``` #### 安全性实现 - **认证机制**:OAuth 2.0、JWT、API Key - **加密传输**:TLS 1.3 协议 - **访问控制**:基于角色的权限管理(RBAC)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值