经过一年时间的沉淀 再次回首 TCP Socket服务器编程 (二)

简介: ------------------前言------------------ 发了第一篇文章后,有不少同志留言,看来socket编程仍然是软件系统里面一个比较难的部分。第一篇文章主要介绍了传输协议的设计,这个是整个socket框架最底层基础的部分,接下来整个socket服务器大楼都将在这个协议设计基础上不断搭建出来。

------------------

前言

------------------ 
发了第一篇文章后,有不少同志留言,看来socket编程仍然是软件系统里面一个比较难的部分。

第一篇文章主要介绍了传输协议的设计,这个是整个socket框架最底层基础的部分,接下来整个socket服务器大楼都将在这个协议设计基础上不断搭建出来。

这篇文章我主要接上文提出的服务器各个性能参数给出解决思路。

 

-------------------

socket服务端接收模块设计 

------------------- 

当服务器Accept一个新的socket之后,会对这个socket进行封装,成为一个connection(当然是自定义了) 。之后的处理都会交给这个connection负责。

由于socket发送的数据存在分包黏包问题,connection接收模块注定了要使用接收队列。当然这个所谓的接受队列并没有大家想象的这么深奥,大致的代码结构如下: 

public class SocketReceiveQueue
{
    private Queue<ISocketReceivePackage> queue = null;
    private MemoryStream receiveBuffer = null;
}

 

即一个queue的接收队列+一个stream。处理逻辑:

  

a. 接收到数据,压入receiveBuffer

b. 从receiveBuffer读取数据、获取协议包ISocketReceivePackage,这里可能会有多个,也可能一个也没有。

c. 当接收完毕后,协议包再从queue出队列,交给注册的协议处理handler处理。

 

到目前为止,整块接收逻辑并没有涉及具体的业务、也绝对不应该涉及具体的业务。唯一要额外注意的就是接收包的长度问题,即协议包声明的length是否过大。

 

这里要注意,由于整个接收模块没有涉及到具体的业务逻辑,也就不应该在这里对任何的输入进行检测(非法攻击、频率等),代码上就是以最快速度解析完协议包,然后丢给上层handler分析。

 

------------------- 

客户端请求性能分析 

-------------------

当协议包来到了与业务相关的Handler之后,我们开始进行性能检测。首先是请求频率,使用如下公式:

 

requestInterval = (requestInterval * requestTimes + interval) / (requestTimes + 1)

 

 

计算得到的requestInterval就是客户端的请求频率。 数学上也很简单,就是一个类似f(x) = af(x)+b的迭代算法。这个算法的特定当然就是性能高,我只需要记录用户当前请求时间、请求累计次数之后,就能完全监控了用户的请求性能。

 

此外还需要记录顾客的错误次数。从设计理论上来说,客户传输过来的数据不应该有错,除非代码出错。当然,如果在值类型之间转换出现的问题算是错误的话(用户正常输入了错误的数值),这个不算入错误。这个错误值是需要记录在数据库里面;一旦发现错误值过大,则直接封这个IP了。

 

还需要说明的是,在服务器一定有一个触发器,每x秒会遍历一次所有的connection,一旦发现有长时间无请求的空连接,要主动踢出。

 

------------------- 

socket服务端发送模块设计 

-------------------

当服务器处理完数据后,需要将处理结果回复给客户端。如果使用简单的设计思路,即直接压入socket发送,性能是非常的低的;因此socket的发送必定需要使用发送队列。使用发送队列的优势在于:

 

 

a. 当服务器内部需要发送的数据激增的时候,通过压入发送队列,能够减轻IO的处理压力。很多时候我们会发现整个服务器的性能瓶颈就在IO的处理上(收发) ,而不是服务器的数据库操作等。因此设计上就要以减轻IO处理为目标。

b. 使用发送队列,能够把多个回复数据包合并一次发送,极大减轻了IO的压力。

 

发送队列的结构也就是一个Queue,大致的设计如下:
复制代码
代码
public class SendMessageQueueController
{
   Queue<SocketConnection> queue;
}


public class SocketConnection
{
    private SocketReceiveQueue receiveQueue;//接收队列
    private SocketSendQueue sendQueue;//发送队列
}

public class SocketSendQueue 
{
    private Queue<ISocketSendPackage> queue;//发送协议集合
}
复制代码

 

代码逻辑如下: 

 

 

a. 把需要发送的协议包压入当前SocketSendQueue.

b. 判断SocketConnection是否已经存在在SendMessageQueueController,如果不存在,则入列;如果存在,则返回。

c. SendMessageQueueController每隔x毫秒检查一次发送队列,如果发现有数据,则进入while循环,直到所有SocketConnection出列并发送所有的数据。之后再进入等待。

d. 所谓包合并发送,就是把多个协议包一次写入发送的Stream里面,然后让socket发送。

 

这块的设计问题主要集中在线程冲突,需要在关键地方加几把锁,否则就容易出现线程冲突了。

 

------------------

后记

------------------

 

本文介绍的方法并不是最好的方法,我也相信业界有更加成熟的思路。不过我文中列举的一些设计思路至少我用起来还是能够满足现有需求的。

 

如果各位同志有更好的思路,希望多多留言指教。

 

在下一篇文章中将结合具体的传输协议开始设计服务端的通用逻辑模块,例如重发、数据缓存、登录登出等。

目录
相关文章
|
2月前
|
Web App开发 缓存 网络协议
不为人知的网络编程(十八):UDP比TCP高效?还真不一定!
熟悉网络编程的(尤其搞实时音视频聊天技术的)同学们都有个约定俗成的主观论调,一提起UDP和TCP,马上想到的是UDP没有TCP可靠,但UDP肯定比TCP高效。说到UDP比TCP高效,理由是什么呢?事实真是这样吗?跟着本文咱们一探究竟!
60 10
|
5月前
|
负载均衡 监控 网络协议
TCP四次挥手:为什么四次?原理大揭密!
**TCP四次挥手详解**:客户端发送FIN进入FIN-WAIT-1,服务器回ACK进CLOSE-WAIT;服务器发送FIN,客户端回ACK进TIME-WAIT,等待2MSL确保数据传输完毕,防止新旧连接混淆。四次挥手确保双方完全关闭连接,解决数据丢失问题。过多TIME-WAIT可通过负载均衡、优化关闭顺序或调整系统参数缓解。关注“软件求生”获取更多技术内容!
137 0
|
6月前
|
运维 网络协议 算法
不为人知的网络编程(十六):深入分析与解决TCP的RST经典异常问题
本文将从TCP的RST技术原理、排查手段、现网痛难点案例三个方面,自上而下、循序渐进地给读者带来一套完整的分析方法和解决思路。
139 0
|
7月前
|
消息中间件 调度
socket长连接所用到的八大技术
socket长连接所用到的八大技术
45 0
|
网络协议
TCP连接的关键之谜:揭秘三次握手的必要性
在这篇文章中,我们将深入探讨TCP连接建立过程中的关键步骤——三次握手。三次握手是确保客户端和服务端之间建立可靠连接的重要过程。通过三次握手,双方可以确认彼此的接收和发送能力,并同步双方的初始序列号,从而确保连接的稳定性和可靠性。文章还解释了三次握手的原因,它可以避免历史重复连接的初始化,确保双方都收到可靠的初始序列号,并避免资源浪费和消息滞留的问题。通过三次握手,TCP连接可以保证数据的准确性和完整性,确保通信的可靠性。
186 1
TCP连接的关键之谜:揭秘三次握手的必要性
|
消息中间件 网络协议 JavaScript
面试官:一台服务器最大能支持多少条 TCP 连接?问倒一大片。。。
面试官:一台服务器最大能支持多少条 TCP 连接?问倒一大片。。。
|
网络协议 网络性能优化
重新认识 TCP 三次握⼿ 和 四次挥⼿
重新认识 TCP 三次握⼿ 和 四次挥⼿
67 0
|
网络协议 Java 程序员
猿创征文|UDP/TCP网络编程
猿创征文|UDP/TCP网络编程
134 0
猿创征文|UDP/TCP网络编程
|
域名解析 缓存 移动开发
揭开tcp&udp协议的真实面貌
tcp需要解决网络不可靠带来的所有不确定因素,作为很多应用层的首选传输协议,udp只管数据的发送与接收,高效的收发机制成为很多通讯应用的首选。
158 1
揭开tcp&udp协议的真实面貌
|
网络协议 Unix Java
TCP学习笔记(一) 初遇篇
TCP学习笔记(一) 初遇篇
TCP学习笔记(一) 初遇篇