首页 > 代码库 > [Java聊天室服务器]实战之五 读写循环(服务端)
[Java聊天室服务器]实战之五 读写循环(服务端)
前言
学习任何一个稍有难度的技术,要对其有充分理性的分析,之后果断做出决定---->也就是人们常说的“多谋善断";本系列虽然涉及的是socket相关的知识,但学习之前,更想和广大程序员分享的是一种心境:学习是一个循序渐进的过程,心态应该随时调节,保持戒骄戒躁的状态。比如最近在看网易公开课MIT《算法导论》,老师提到,学习算法之前要计算机数学+离散数学+概率论等课程的知识,所以一直学不好算法的程序员不妨从基础入手,这都是中国式教育惹的祸啊!(此处省略一万字......)
项目源码:Socket_Chat
目录
- [Java聊天室服务器]实战之一 开篇介绍(已完成)
- [Java聊天室服务器]实战之二 监听类(已完成)
- [Java聊天室服务器]实战之三 接收循环(已完成)
- [Java聊天室服务器]实战之四 线程类(已完成)
- [Java聊天室服务器]实战之五 读写循环(服务端)(已完成)
- [Java聊天室服务器]实战之六 去除死链接(未完成)
- [Java聊天室服务器]实战之七 客户端类(未完成)
- [Java聊天室服务器]实战之七 读写循环(客户端)(未完成)
正文
通信协议
现在我们已经了解从哪里和客户端连接,应该谈一谈我们的通信协议
每一个客户端/服务端 系统都会有一个通信协议,它只是用于传输信息到前端和后台的格式。协议可以很简单但很难得到小块协议,或者它很标准精妙以至于已经在全世界内协会正式批准。反正,它是一个协议。
我们将要我们自己的协议,因为在Java语言中是很容易做到的,而且付出一点就可以得到已经存在的标准协议。我们的协议会非常简单。
Java语言有一套非常有用的类,称做DataInputStream 和DataOutputStream。这些类允许你读取和输出底层数据对象(比如整形和字符串)到流中,不考虑它们输出的格式。由于这些类使用相同的格式,而且格式是不会改变的,你可以肯定整数会被写入DataOutputStream,在另一方面会从DataInputStream读出。
我们的协议会是这个样子:
- 当用户在聊天窗口输入某些事情时,他们的信息作为字符串通过DataOutputStream 传递。
- 当客户端通过DataInputStream接收信息,它会发送相同的信息给所有用户,同样也会作为字符串通过DataOutputStream传递。
- 用户使用DataInputStream接收信息。
协议就是这样!
—————————————————————————————————————————————————————————————————————————
什么是线程?
Java语言的两个主要优点:网络和多线程。也不是说其他语言就不支持上面的功能 -- 它们也支持。但是Java语言的抽象可以很简洁地提供这些功能,特别对于商业语言来说。
线程一般定义为单个进程里面独立的控制线。真实的意思是说在同一时间,多线程的程序具有多线程,在其内部具有半自主活动的特点。
多线程类似于一个任务和多任务的概念,除了在一个程序中的多个线程可以共享相同的数据空间的不同。并且这样让风向数据更加直接和有效率 -- 同样变得更加容易混乱,不受控制。
—————————————————————————————————————————————————————————————————————————
循环
现在我们进入核心服务端循环 -- 这是真正聊天工作的代码,让我们看一看:// 当构造函数调用start()的时候,会在单独的线程里 public void run() { try { // 为通信创建DataInputStream;客户端使用DataOutputStream输出给我们 DataInputStream din = new DataInputStream(socket.getInputStream()); // 一直循环 while (true) { // ... 读取下一条信息 ... String message = din.readUTF(); // ... 输入到控制台上 ... System.out.println("Sending " + message); // ... 服务端发送它给所有的客户端 server.sendToAll(message); } } catch (EOFException ie) { // 不需要错误信息 } catch (IOException ie) { // 需要错误信息,输出至控制台 ie.printStackTrace(); } finally { // 因某种原因,连接会关闭,所以服务端会处理它 server.removeConnection(socket); } }
你会注意到我们在多个地方使用了务端对象。
第一个地方时当我们调用server.sendToAll()。实际上是一个很方便的函数。我们会请求服务器列举所有连接另一面的OutputStreams,然后把这些信息写入到这些流中。但是因为这么做是很频繁,我们把所有的这么工作放到服务器这端,sendToAll()方法里面。
—————————————————————————————————————————————————————————————————————————
结束语
第二个使用服务端对象的地方会在下一节中提到。
参考文献
[1]. Building a Java chart server
[2]. Java sockets 101以及中文系列 JAVA套接字(Socket)101
[3]. Java socket通信基本原理介绍