声明:该文章为原创,且只适合基础浅薄的初学者阅读,该文章中没用使用任何较为复杂的操作和技巧,只为初学者快速理清多人聊天的实现思路。
首先在了解多人聊天室实现思路之前,我们先要搞清楚双人聊天的机制,即单一客户端与服务器进行的交互思路:
首先服务器端要实例化一个ServerSocket对象,并用其中的accept()方法等待客户端的连接。
这里值得注意的是:ServreSocket类中的accept()方法是一个阻塞方法,也就是说accept()方法在获取客户端的连接之前会一直进行阻塞式的等待,不会让其下面的代码执行,直到得到客户端的连接为止。
服务器一直等待的同时,我们就要建立客户端并向服务器申请连接。那么在客户端代码中,我们要实例化一个Socket对象,其应该具有和服务器端ServreSocket相同的端口号,以此确保对服务器提出准确的连接。在成功实例化创建Socket对象后,就相当于成功和服务器建立了连接(前提是申请的服务器对象已创建并在执行accept()方法等待)。
在客户端成功提出连接申请后,我们再回到服务器端accept()方法上来,accept()方法在成功得到连接申请后,返回的值是一个Socket对象,该Socket对象是通向该客户端的连接。
在成功通过Socket对象和ServerSocket对象在客户端与服务器间建立TCP连接后,我们就要开始进行服务器与客户端间的信息交流了,其手段则是通过IO流的实现: 通过Socket类中的getInputStream()方法和getOutputStrea()方法可以获取对应方向的输入流和输出流。
服务器端通过对accept()得到的Socke对象使用getOutputStrea()方法创建的OutputStream流可以向客户端写入信息,同理对该Socket对象使用getInputStream()方法获取的InputStream流可以从客户端中读取信息。反之客户端亦然。
到此我们成功实现了客户端与服务器之前有顺序的一读一写的功能思路。不过存在的问题也同样十分明显:即就是我们假若先让客户端向服务器写数据,再从服务器中接受数据,那么服务器也必须先等待客户端写入的数据,再向客户端写数据,这样一来读写的顺序就被固定了,无法实现同时进行随意的读写操作。
在此做一点补充:IO流的read()方法其实也是一种阻塞方法,即就是read()会一直等待流中信息的到来并进行读取,如果没有信息从流中过来,它就会对线程进行阻塞并一直等待。
要实现两端随意的无顺序读写操作,也就需要使用多线程的操作。我们的思路是:读和写的操作分开,分成两个相互独立的线程同时进行,以达到读写并行,互不干扰的目的。
具体的思路是:
以上两个思路的线程并发进行,则可以实现服务器对客户端的同时读取与写入操作,客户端对服务器的操作完全可以照搬以上操作,这里就不再赘述。
这会至此,我们终于实现了服务器和客户端两个对象之间的随意的信息交互功能。
在大肆铺垫之后,终于进入正题:
现在我们需要思考多人聊天和双人聊天之间的区别,此前我们实现的客户端与服务器间交互的思路是:服务器接受到另一端的信息后只给服务器自己看到就可以了,而现在不同了,现在要实现群聊的功能,那么服务器在接受到任何一个客户端发来的消息之后,就要让所有连接服务器的客户端都看到这条消息,那么服务器就要进行转发操作。服务器的转发操作就是实现多人聊天的关键:
以上就是服务器的转发操作,客户端的操作相对于之前基本没有变化,还是保持两个独立的线程实时对服务器中传来的信息进行监听并等待控制台输入的数据对服务器发送即可