利用局域网聊天程序来锻炼j2se---------之挑战所有你心目中的高手
写之前思考了一下,本打算发布一下最终版本,并附带所有的注释就算大功告成了.
后来细细想了下,这样的聊天程序网上很多,同时,对于只看我注释来学这个项目的人来说,他即便看懂看会,
还只能是依葫芦画瓢,不懂一步步创建的原理和调试的方法.
所以今天,我会带着大家把开发局域网聊天的详细思路和步骤用文字和代码一句句写出来,同时发布最终版无注释代码,
此目的也是让大家自己读懂每个代码段为什么要这样写的原由.
好了下面就开始吧.
首先利用Eclipse新建一个项目,同样在项目里面新建一个类,这里的具体步骤我不多说了,相信大家都比我清楚.
做之前先思考下,第一步先做什么?
聊天程序我们直观的来说就是可以有个输入栏发布消息,同时能在另一个界面上看到自己已经发布的消息从而确认发布出去了.
好,那么首先做的就是画一个你认为满意的窗口.
Frame 图形窗口类,根据我的笔记gui这课,我想你应该能画出来.
特别照顾下不喜欢查jdk帮助文档的朋友,TextField是单输入栏.TextArea是多行输入栏.(我怎么知道的,查的呗)
我简单画了个大概,大家比较下.
import java.awt.*;
public class Client extends Frame {
//由于聊天系统有一个用户的输入框,那么就用输入栏TextField类来编写
//为什么写在成员方法里,那是因为方便被窗口方法调用
TextField text=new TextField();//建立了text文本输入对象
//由于上面的是单行,作为用户输入可以,但显示栏就不行,所以必须找个多行的方法
TextArea teext=new TextArea();//多行文本编辑器
public static void main(String[] args) {
new Client().launchFrame();
}
public void launchFrame() {
// 由于对相关方法不熟悉,用this来使得有代码提示。
// 设置窗口,首先是确定位置,如果不确定,那么默认是左上角
this.setLocation(300, 200);// 移到新位置//从Component继承的
// 下面要设置窗口的大小
this.setSize(244, 366);// 调整大小//window类继承的
// 为了不让用户自己变化窗口的大小,所以要限制大小不能变化
this.setResizable(false);// 设置此窗体是否可由用户调整大小//自己的方法
// 显示窗口可以设置不同的颜色来增加视觉效果,当然,这里还是设置为默认的白色
this.setBackground(Color.white);// 设置背景色//Component类继承
//加载并设置输入栏位置,注意布局管理器的运用
this.add(text,BorderLayout.SOUTH);//这里,把输入栏载入到窗口,同时用布局管理器设置在南边
this.add(teext,BorderLayout.NORTH);//注意,鼠标输入筐是按照第一个设置哪个输入栏而默认的
//由于上面两个输入栏都是默认的大小,所以对于窗口来说高度不一定合适,所以在没有设置输入栏大小的时候用自动设置来的比较方便
this.pack();//自动 设置大小
this.setVisible(true);// 把上面的所有设置的结果 显示出来//Window 类继承
}
}
注释写的太多影响观看了,后面尽量少写点,恩.
下面我们运行下刚才的程序,有两个输入栏,同时也都能写文字,这时,我们去关闭该程序,发现他关不掉,只能在控制台中结束.那怎么办呢?
大家应该想起我的笔记上说过的监听类吧.那关闭窗口也有他的监听类和接口.不熟悉的朋友请回头看下我的笔记.恩
查找java.awt.event 图形事件包
找到WindowListener用于接收窗口事件的侦听器接口.
然后找到 windowClosing(WindowEvent e) 方法,由于该方法是 WindowAdapter继承下来的子方法.
所以我们创建WindowAdapter方法并实现windowClosing方法的操作,这样可以避免所有的方法都一一实现.
说到这,大家考虑下怎么写,写监听有三个方法,第一是写个并排的外部类,以后别的方法也可以调用.
第二是写个内部类,可以针对主方法做更多的方法实现.当然还有第三个就是写个匿名类.尽量不做其他的处理用.
考虑了一下,我想还是用匿名类比较合适.本程序在关闭事件上就只打算简单的实现关闭操作.
好具体写法如下:
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
// TODO 自动生成方法存根
System.exit(0);
}
});
顺带说下,如果你还没用Eclipse工具的话,请赶紧开始用它.应为windowClosing方法是通过编辑器来生成的.
下面考虑一个问题,我们需要在单文本输入栏上写东西,然后一敲回车,文字得移动到上面的多文本编辑框上.
这里又要使用另外一个监听器接口 ActionListener用于接收操作事件
考虑下这里具体该怎么写.
由于我们要输入文字,以后可能还要包装成管道流输出等,代码量会比较多,所以匿名类在这里就不会太方便了.
所以内部类是最好的方法
private class list implements ActionListener{
public void actionPerformed(ActionEvent e) {
//先获取输入栏的字符放到ss中
String ss=text.getText().trim();//去掉两边的空格后的字符串
//再把字符到多行输入栏显示出来
teext.setText(ss);
//然后把单行输入栏设置空
text.setText("");
}
}
同样,内部的方法通过编译器可以自动调出.好了,同时在显示窗口之前调用该方法.
text.addActionListener(new list());
^-^知道在哪里加入吧.
写到这里,我们可以在输入栏写东西并敲入回车把文字在多行输入栏显示出来了.
现在应该是考虑服务端的制作了.首先要做的是如何使得服务端和客户端连接起来.
java.net.*;网络应用程序提供类包在服务端要用到了.
import java.net.*;
public class Server {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(8888);
while(true) {
Socket s1 = ss.accept();
System.out.println("一台客户端连接上来了");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
上面是简单做了个通讯端,当然程序后面会改进他.
这里要注意的是服务端实现了accept()侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。
至于try catch那些语句,在Eclipse中也会帮你自动生成.你只需要注意关键语句的地方就可以了.
好,既然服务器端提供了端口和监听方法,那么就开始等待客户端发送地址端口上来了.
可以写成方法,方便以后调用观看.对了知道该方法放哪里吧.显示窗口结束后就可以用它了.
public void connect() {
try {
Socket s2 = new Socket("127.0.0.1", 8888);
System.out.println("客户端启动!");
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
看看上面的语句,其实只有一句话是重点,哪句呢?
s = new Socket("127.0.0.1", 8888);//创建发送地址端口
其他的都是eclipse帮你完成的,只要记得Ctrl+1快捷键的使用就可以了.
大家可以运行服务端后接着运行客户端程序.恩,到此,简单的客户端和服务端连接就算完工了.
好下面要思考下,如何能在客户端发送一句话,服务端能收到.
注意:为什么不是一个客户端发一句话另一个客户端收到呢?
应为所有客户端之间的交流都是先发送到服务端,然后再由服务端发送到客户端上的.
既然是客户端在输入栏写一段话,然后一回车,服务端收到,那么大家想想,以前网络这节讲的内容.
首先我们要把客户端的 Socket 的s2,往外发送.
s2.getOutputStream();//返回此套接字的输出流。为了直接往外发送一个字符串,
所以使用DataOutputStream把它变成流.这样就可以用writeUTF了.
具体写法是 DataOutputStream dos = new DataOutputStream(s2.getOutputStream());
这里我们要注意的是,由于该实现是在输入栏监听事件方法中编写的,所以无法取得connect方法中的,Socket.
那么怎么办呢?我们可以把Socket定义为成员变量并为null.在connect方法中就不必再单独定义了.
以下是list下的具体代码
DataOutputStream dos = new DataOutputStream(s2.getOutputStream());
dos.writeUTF(ss);
dos.flush();
dos.close();
下面看下服务端应该怎么接收.在accept监听后.
DataInputStream dis = new DataInputStream(s1.getInputStream());
String str = dis.readUTF();
System.out.println(str);
dis.close();
这些运用我就不解释了,笔记上都有.
好下面大家完成以上的程序代码,并测试下,当输入一次时可以在服务端显示,但 当第二次输入时候,却发现出错了.
好讲解上面留下来的问题,第一次输入的时候,服务端是正常的,为什么到了第二次就出现不正常了呢?
大家通过出错的信息,可以连接到是在DataOutputStream dos = new DataOutputStream(s2.getOutputStream());
这里出的错,那么,具体分析下,我们第一次输入回车,显示正常,第二次呢?
对了,第二次之前,他已经关闭了.dos.close();大家看到了吧.所以,网络上关闭后需要重新连接才能拿到.
所以简单的操作就是 把 dos.close();去掉.同时,我们把DataOutputStream创建放到成员变量区里面.目的是不用每次都创建.
然后在连接的时候初始化一下,就可以了.连接地方是connect方法内,应该都知道的吧.
那么list里客户端往外发送还保留哪些代码呢?
dos.writeUTF(ss);
dos.flush();
就两个,对吧.
好那么关闭的时候顺便把里面资源清理一下.
写一个方法,在窗口关闭的时候调用他.
public void disconnect() {
try {
dos.close();
s2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
好,接下来我们再看下服务端,由于客户端发送了多次数据,服务端就必须接受多次数据,那么
readUTF就要多次使用,那么这里,我们就要用一个循环来多次接受客户端的数据.
修改之后的服务端代码如下:
import java.net.*;
public class Server {
public static void main(String[] args) {
boolean started
局域网聊天程序详情 j2se
需积分: 9 129 浏览量
2009-10-11
08:05:10
上传
评论
收藏 7KB RAR 举报
twtd5
- 粉丝: 0
- 资源: 10
最新资源
- 王姿.html
- 51单片机学习(1)-软件keil下载
- 历届(第1-21届)希望杯数学竞赛初一试题及答案(最新整理).doc全国数学邀请赛(264页资料)
- 水滴.psd
- TokenPocket_V2.1.2_release.apk
- Apache-druid-kafka-rce.yaml
- 基于C#的ASP.NET数据库原理及应用技术课程指导平台的开发
- 基于ROS的智能车轨迹跟踪算法的仿真与设计源码运用PID跟踪算法.zip.zip
- Bug Bounty Tip - i春秋Self-XSS变废为宝的奇思妙想
- 1991-2015年全国初中化学竞赛复赛试题汇编(212页)(24年竞赛复赛真题).docx天原杯
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈