浅谈网络客户端的类库编写和使用

简介: 我们知道TCP连接的代价是比较大的,因此很多时候我们都会使用长连接,对于客户端也就会使用连接池。 而各种客户端实现的方式不尽相同,API的最佳使用方式也不尽相同,如果使用不当则会发生很大的问题。 比如,在每次连接服务端的时候都初始化连接池,每次使用之后释放连接池,那么会导致很可怕的性能问题。

我们知道TCP连接的代价是比较大的,因此很多时候我们都会使用长连接,对于客户端也就会使用连接池。

而各种客户端实现的方式不尽相同,API的最佳使用方式也不尽相同,如果使用不当则会发生很大的问题。

比如,在每次连接服务端的时候都初始化连接池,每次使用之后释放连接池,那么会导致很可怕的性能问题。

又比如,在每次用完连接池中的连接后没有能把连接归还,那么连接池会认为这个连接在使用,从而创建越来越多的连接。

其实很多时候用户对于类库的使用不当也体现了类库的设计不当。

现在我们来看几个不太好的设计:

1) 某个应用提供了一个Client类下面提供了若干API,比如:

Client client = new Client();

Database db = client.GetDatabase();

db.Open();

db.Add();

但用户不知道Client构造的时候会初始化一个连接池,这样相当于没一次调用创建10个连接,然后废弃。

效率极差,其实Client类提供了静态入口Instance,但是Client没有关闭构造方法,导致了这个问题。

在private构造方法之后,就只能通过Client client = Client.Instance来获取了,避免了这个问题。

2) 还是这个应用,它为Client类提供了Disconnect()方法,开发人员这么使用:

Client client = Client.Instance;

Database db = client.GetDatabase();

db.Open();

db.Add();

client.Disconnect();

而在Disconnect内部其实是释放了连接池,在Add方法中判断如果没有可用连接则创建。

那么这样也就相当于每次都会创建10个连接,性能同样非常差。

其实Client类不应该有Disconnect实例方法。注释了最后一行后问题解决。

(该释放的不释放,不该释放的释放了)

3) 即使这样还有问题,在调用Add方法之后,系统抛出异常,不能对未打开的数据库执行操作。

开发人员很容易想到去调用Open或Connect之类的方法。

但是最后却忘记调用Close()了,由于连接池设置了10000的上线,并且启用了5分钟空闲就回收的机制。

所以系统一开始上线并没有出现问题,但是运行一段时间之后时不时会出现连接池满的问题。

在db.Add()之后调用db.Close()解决问题。

其实,类库的设计人员在在Add方法内部进行连接的获取和回收那多好啊?

即使不知道操作的边界,也应该提供一个IDisposable的Database类。

那么现在就可以回答这些问题了:

1) 连接池的初始化方法应该怎么实现?是静态方法还是实例方法?

宗旨:连接池相对唯一,绝不能每次使用创建,每次用完关闭。

个人认为,不提供连接池的初始方法 > 静态方法 > 实例方法。

因为连接池本来就是一个内部的实现,作为类库的调用放本不应该知道怎么去使用。

在万不得已的情况下,API入口方法也应该以静态方法提供。

因为如果提供了非静态的方法,API的使用者很可能会尝试调用Close之类的Dispose方法去关闭连接池,释放所有连接。

(当然,不应该提供或谨慎提供连接池的Dispose是后话了)

2) 连接池的重置方法应该怎么实现?

个人认为最好不要提供,如果一定要提供那么就在单独的辅助方法中提供,避免误调用。

3) 涉及到操作的方法应该怎么实现?IDisposable?

涉及到操作的方法往往关联了连接的获取和释放。对于使用连接池的实践来说,应该尽早返回,尽量晚获取。

可以实现IDisposable要求开发人员确保连接在用完之后返回。

个人认为最好的方式还是直接提供静态API,在内部包装连接的获取和返回。

避免万一调用者没有Dispose的情况,对于特殊情况比如要求持续使用一个连接可以考虑创建一个IDisposable的OperationScope的类。

作为类库的编写者不但应该在设计类库上尽量考虑调用者的习惯和方便而且也应该在类库文档中提供最佳实践,避免一些悲剧的发生。

随着越来越多的开源服务端出现,开源的客户端也越来越多了,但是其中的实现各不相同,在使用之前还是应该大致了解使用实践,毕竟不是所有的开源客户端的API都像微软那样人性化的。

作者: lovecindywang
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
【计算机网络】如何让客户端构造一个HTTP请求-2
【计算机网络】如何让客户端构造一个HTTP请求-2
【计算机网络】如何让客户端构造一个HTTP请求-2
|
3月前
|
开发框架 Java 测试技术
SpringBoot3 响应式网络请求客户端
SpringBoot3 响应式网络请求客户端
|
3月前
Socket网络编程练习题四:客户端上传文件(多线程版)
Socket网络编程练习题四:客户端上传文件(多线程版)
|
3月前
Socket网络编程练习题三:客户端上传文件到服务器
Socket网络编程练习题三:客户端上传文件到服务器
|
3月前
|
存储 前端开发 JavaScript
【计算机网络】如何让客户端构造一个HTTP请求-1
【计算机网络】如何让客户端构造一个HTTP请求-1
【计算机网络】如何让客户端构造一个HTTP请求-1
|
3月前
|
Java
Socket网络编程练习题五:客户端多用户上传文件(多线程版)并使用线程池管理线程
Socket网络编程练习题五:客户端多用户上传文件(多线程版)并使用线程池管理线程
|
3月前
|
网络协议 安全
网络编程-TCP协议(客户端和服务端)
网络编程-TCP协议(客户端和服务端)
|
1月前
|
监控 网络安全 C++
Qt 5.14.2 网络编程揭秘:构建高效HTTP客户端与文件下载器
Qt 5.14.2 网络编程揭秘:构建高效HTTP客户端与文件下载器
|
1月前
|
JSON Go API
Go语言网络编程:HTTP客户端开发实战
【2月更文挑战第12天】本文将深入探讨使用Go语言开发HTTP客户端的技术细节,包括发送GET和POST请求、处理响应、错误处理、设置请求头、使用Cookie等方面。通过实例演示和代码解析,帮助读者掌握构建高效、可靠的HTTP客户端的关键技术。
|
3月前
|
前端开发 Java Maven
【Netty 网络通信】启动客户端连接服务端实现通信
【1月更文挑战第9天】【Netty 网络通信】启动客户端连接服务端实现通信