Content Table

广播

“安红,额想你” 这句话曾经红的一塌糊涂,以至于人们只记住了这句话而忘了出自这句话的电影《有话好好说》:张艺谋骑着个破三轮出场,用陕西话喊:“安红,俺想你,想你想得想睡觉”:

注意,老谋子手里有个大喇叭,对着喇叭一喊,那就炸了锅了,周围的人都听到了。Broadcast 和用喇叭喊话很相似,消息一发送,就能被同一个局域网里的所有电脑收到。对着喇叭喊话对应于发送 Broadcast 消息,周围对应于局域网,声音的传递是有范围的,Broadcast 的消息也只能是局域网内被收到。

Clip 实现复杂绘图效果

经常会遇到有人问,用 Pixmap 绘制图像已经知道了,但是怎么绘制一个圆的图像呢?就像 QQ 头像那样,即使上传的头像是一个矩形的,但是显示出来的效果是圆形的,也就是说,在圆的范围内绘制图像,图像超过圆范围的部分不绘制,就像下图的效果

单播

使用 Unicast 的时候,Source 一次只能给一个 Destination 发送消息,不能同时发给多个 Destination,如果 Source 要给多个 Destination 发一条内容相同的消息,就必须单独地分别给每个 Destination 发送这条消息。

UDP 编程

UDP 是 User Datagram Protocol 的简称,中文名是用户数据报协议,是一种无连接的不可靠协议,也既是说,数据发出去了,但是不能保证对方一定能接收到,就像寄信一样,虽然把信交给了邮局,中途有可能寄丢。

UDP 报文没有可靠性保证、顺序保证和流量控制字段等,可靠性较差。但是正因为 UDP 协议的控制选项较少,在数据传输过程中延迟小、数据传输效率高,适合对可靠性要求不高的应用程序,如果既要使用 UDP 高效的同时也想要保证数据的可靠性,那么就需要在应用程序中对收发的数据进行验证,这样的程序有很多,例如 DNS、TFTP、SNMP 等。

网络编程

网络通讯无处不在

  • 用 QQ 和朋友聊天,发文字,发图片,发文件,语音聊天,视频聊天,然而,对方的 QQ 是怎么接受到我们发送的数据呢?
  • 用浏览器上网,网页上的图片,JavaScript 文件,CSS 等是怎么下载来的呢?
  • 使用 FTP 工具下载服务器上的文件
  • 用 BT 软件下载电影
  • 在线看电影,听歌
  • 玩网络游戏
  • 软件在线升级

用到网络通讯的地方太多太多,举不胜举,如果没有网络,电脑不能上网,手机不能上网,不能玩网络游戏,不能淘宝,不能在 12306 买火车票,不能百度,不能在线学习,不能用百度地图,不能团购,不能……,这样的世界将会是多么的无趣!

网络编程大家应该都听过 UDP,TCP,也许你还知道如 FileZilla 是用 FTP 传输协议来上传下载文件的,浏览器使用 HTTP 协议和服务器交互,BT 软件使用 P2P 协议下载文件,QQ 有自己的通讯协议,不同的软件很有可能定制了自己的传输协议,从网络上搜素,可以看到各种各样的协议,还有程序之间使用 MQ 通讯,网络通讯的库 Netty,Mina,高性能 TCP/UDP Socket 组件 HP-Socket,也许看到别人介绍网络编程时可能用到 FlatBuffers 等。

看的头都大了,我就是想写个小程序,在 2 台电脑之间发个文字消息,难道要了解上面这些各种各样的东西?吓得赶快去写个单机程序压压惊!

其实上面说的形形色色的东西,他们底层数据的传输都只是用了 2 个东西:UDP 和 TCP,完成上面发消息的这个小程序,只要了解基础的 UDP,TCP 编程就够了。所谓的通讯协议如 HTTP,FTP,P2P 等没有什么神秘的,他们定义的只不过是一个数据结构,某几个字节表示的是什么数据,有的数据项多些,有的数据项少些而已,数据按照通讯协议组织后使用 UDP 或者 TCP 来传输,对方接收到数据后,根据协议定义的格式解析数据,协议就是网络通讯中用的语言,只有语言通了,才能交流,否则就是鸡同鸭讲,不知所谓。

网络编程我们会介绍 UDP,TCP 基础编程,自定义通讯协议,使用 FlatBuffers 简化数据的序列化和反序列化,还会介绍使用 MQ 在不同的语言编写的程序之间进行网络通讯。

单例的其他实现

单例还有没有其他的实现方式?
有,我们的实现,使用的就是传说中的懒汉方式,还有饿汉方式,实现也挺简单的

1
2
3
4
5
6
7
1. 把单例的简单实现中的
static QMutex mutex;
static ConfigUtil *instance; // ConfigUtil 全局唯一的变量
换成
static ConfigUtil instance;

2. getInstance() 直接返回这个 instance 即可,还没有线程同步的问题

此外,还可以直接在 getInstance() 函数里定义一个静态的 ConfigUtil 变量(具体的可以参考 Qt 的宏 Q_GLOBAL_STATIC 的实现)。

单例的智能指针+宏的实现

如果要创建一个单例的数据库连接池 ConnectionPool,那么实现单例部分的代码和 ConfigUtil 的几乎一样,声明 private 的构造函数,拷贝构造函数,析构函数,赋值操作符,QScopedPointer instance,friend struct QScopedPointerDeleter,几乎完全一样的 getInstance() 等,这些代码几乎都是重复的,每个单例的类这些内容都重复一遍,违背了代码的复用原则。为了实现代码复用,可以用继承、函数、宏定义、模版等。对于单例,继承很难达到目的,这里我们选择使用宏来实现代码复用的目的,后面的章节会介绍使用模版的实现。

单例的智能指针实现

前面提出了一个问题:可不可以不需要我们手动的调用 release() 函数,程序结束前自动的删除单例类的对象呢?答案是可以,使用智能指针可以达到这个目的,这里我们使用的是 Qt 的 QScopedPointer 来实现,也可以使用标准的 C++ 的智能指针。