在本章5.2.2的实例中,Server和Client只是进行了简单的通信操作,当服务器接收到客户端连接之后,服务器向客户端输出一个字符串,而客户端也只是读取服务器的字符串后就退出了。在实际应用中,客户端可能需要和服务端保持长时间通信,即服务器需要不断地读取客户端数据,并向客户端写入数据,客户端也需要不断地读取服务器数据,并向服务器写入数据。
当使用readLine()方法读取数据时,如果在该方法成功返回之前线程被阻塞,则程序无法继续执行。所以此服务器很有必要为每个Socket单独启动一条线程,每条线程负责与一个客户端进行通信。另外,因为客户端读取服务器数据的线程同样会被阻塞,所以系统应该单独启动一条线程,该线程专门负责读取服务器数据。
假设要开发一个聊天室程序,在服务端应该包含多个线程,其中每个Socket对应一个线程,该线程负责读取Socket对应输入流的数据(从客户端发送过来的数据),并将读到的数据向每个Socket输出流发送一遍(将一个客户端发送的数据“广播”给其他客户端),因此需要在服务端使用列表(List)来保存所有的Socket。在具体实现这个聊天室程序时,为服务器提供了如下两个类。
□创建ServerSocket监听的主类。
□处理每个Socket通信的线程类。
接下来介绍具体实现流程,首先看下面的一段代码。
源码路径:daima\5\tcpudp\src\liao\server\IServer.java
在上述代码中,服务端只负责接受客户端Socket的连接请求,每当客户端Socket连接到该ServerSocket之后,程序将对应Socket加入socketList集合中保存,并为该Socket启动一个线程,该线程负责处理该Socket所有的通信任务。
然后看服务端线程类文件的主要代码。
源码路径:daima\5\tcpudp\src\liao\server\Serverxian.java
在上述代码中,服务端线程类会不断读取客户端数据,在获取时使用readFromClient()方法来读取客户端数据。如果读取数据过程中捕获到IOException异常,则说明此Socket对应的客户端Socket出现了问题,程序就会将此Socket从socketList中删除。当服务线程读到客户端数据之后会遍历整个socketList集合,并将该数据向socketList集合中的每个Socket发送一次,该服务线程将把从Socket中读到的数据向socketList中的每个Socket转发一次。(www.xing528.com)
接下来开始客户端的编码工作,在本应用程序的每个客户端中应该包含如下两个线程。
□第一个:功能是读取用户的键盘输入,并将用户输入的数据写入Socket对应的输出流中。
□第二个:功能是读取Socket对应输入流中的数据(从服务器发送过来的数据),并将这些数据打印输出。其中负责读取用户键盘输入的线程由Myclient负责,也就是由程序的主线程负责。
客户端主程序文件的主要代码如下。
源码路径:daima\5\tcpudp\src\liao\server\Iclient.java
在上述代码中,当线程读到用户键盘输入的内容后,会将用户键盘输入的内容写入该Socket对应的输出流。当主线程使用Socket连接到服务器之后,会启动ClientThread来处理该线程的Socket通信。
最后编写客户端的线程处理文件,此线程负责读取Socket输入流中的内容,并将这些内容在控制台打印出来。具体代码如下。
源码路径:daima\5\tcpudp\src\liao\server\Clientxian.java
上述代码能够不断获取Socket输入流中的内容,当获取Socket输入流中的内容后,直接将这些内容打印在控制台。先运行上面程序中的IServer类,该类运行后作为本应用程序的服务器,不会得到任何输出。接着可以运行多个IClient——相当于多个聊天室客户端登录该服务器,此时可以看到在任何一个客户端通过键盘输入一些内容后单击<Enter>键,将可看到所有客户端(包括自己)都会在控制台收到他刚刚输入的内容,这就简单实现了一个聊天室的功能。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。