前言
学习任何一个稍有难度的技术,要对其有充分理性的分析,之后果断做出决定---->也就是人们常说的“多谋善断";本系列虽然涉及的是socket相关的知识,但学习之前,更想和广大程序员分享的是一种心境:学习是一个循序渐进的过程,心态应该随时调节,保持戒骄戒躁的状态。比如最近在看网易公开课MIT《算法导论》,老师提到,学习算法之前要计算机数学+离散数学+概率论等课程的知识,所以一直学不好算法的程序员不妨从基础入手,这都是中国式教育惹的祸啊!(此处省略一万字......)
原文地址:Building a Java chart server[1]
项目源码:Socket_Chat
目录
正文
客户端类
相信与否,我们已经完成创建聊天系统服务端方面的内容。我们有一个对象(服务端)监听新的连接和一些连接对象(服务端线程)处理它们自己的连接。
但是关于客户端方面呢?
我们的客户端会是applet,因为我们假设使用Java语言的一些原因是你想你的程序可以在Web页面运行。
不仅仅只有这一种方式 -- 客户端仅作为一个标准-独立的程序,运行在想服务端一样的自己线程中。如果我们继续这么写,那么下面会有一些不同的讨论。
—————————————————————————————————————————————————————————————————————————
构造函数:建立接口
我们的客户端有图形化界面(GUI),因为它必须和用户整洁的交互。服务端可以使命令行的接口,因为一旦它启动了,用户(或者管理员)不需要其他任何事情。但是整体的客户端方面是我们的用户交互。
我们客户端的第一件事情是建立接口:
我们不会谈它的过多细节,除了说一些,我们的聊天窗口包含一个输入框,为了键入新信息,而且在窗口上给其他用户显示信息。每次用户在输入域中键入某些字符,该字符串会被传递到processMessage()方法中。// 构造函数 public Client( String host, int port ) { // 创建窗口 setLayout( new BorderLayout() ); add( "North", tf ); add( "Center", ta ); // 我们想要接受信息,当某人输入一行点击发送,使用匿名类作为回调函数 tf.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { processMessage( e.getActionCommand() ); } } ); // ...
—————————————————————————————————————————————————————————————————————————
构造函数:连接服务端
构造函数的下一件事情是初始化连接服务端,如下所示:注意我们已经创建了单独的线程处理传入的信息。我们在下一节中做这件事。// 连接服务端 try { // 初始化连接 socket = new Socket( host, port ); // 我们得到一个连接,输出至控制台! System.out.println( "connected to "+socket ); // 让我们抓住流,为他们创建数据输入流/输出流 din = new DataInputStream( socket.getInputStream() ); dout = new DataOutputStream( socket.getOutputStream() ); // 为接收数据开启后台线程 new Thread( this ).start(); } catch( IOException ie ) { System.out.println( ie ); } }
—————————————————————————————————————————————————————————————————————————
用户输入
applet作为组件嵌入进大型GUI框架中。在这个框架中,代码通常响应输入事件接受GUI窗口程序的动作。applet处理事件,做需要做的事情,然后返回,一直等待系统发送另一个事件。
在这个案例当中,用户可能在输入区域键入某些东西。触发器会调用在构造其中创造的匿名内部类。匿名内部类,反过来说,调用processMessage(),也是我们创建的方法。
这个方法传递用户键入的字符串。这个方法很简单:写进字符串到服务端,清空文本输入框让用户可以继续键入其他的信息。下面是代码:
// 当用户键入信息时会调用该方法 private void processMessage( String message ) { try { // 发送信息至服务端 dout.writeUTF( message ); // 清空文本框 tf.setText( "" ); } catch( IOException ie ) { System.out.println( ie ); } }
—————————————————————————————————————————————————————————————————————————
后台线程
我们的程序不会一直等待GUI事件。它也为网络事件做准备。也就是说,等待从服务端来的数据。而且由于我们还没有在框架内创建毁掉函数,接受这些信息,我们已经自己建立好了。记住最后一件事情,我们的构造器会创建一个新的线程,有一点类似服务端做的事情。但是,有一个非常不同的原因,就是我们作为applet运行。
—————————————————————————————————————————————————————————————————————————
结束语
在这个案例中,我们创建了后台线程,这样就可以循环读取,在下一节中我们会提到该方面的知识。
参考文献
[2]. Java sockets 101以及中文系列 JAVA套接字(Socket)101
[3]. Java socket通信基本原理介绍