今天开始自己学习java后第一个小项目的编写——“一个小型的聊天窗口互动小模型”,从昨天晚上开始看有关内容,今天早晨继续,算是完成了最初步的一些工作...现在来做一个小小的总结:
Chat0.1版本: 仅仅是new出来一个Frame的窗口,作为Client端;
Chat0.2版本: 在此Frame窗口内添加了TextFiled和TextArea,完善了Client端窗口的搭建。
Chat0.3版本: 仅仅添加了一个匿名类完成对Client端的关闭工作。
Chat0.4版本: 完成将TextField中输入的内容,显示到TextArea中的功能。
在这里,我将这4个版本合在一起,称为MyChat0.1版本:
import java.awt.*;
import java.awt.event.*;
public class ChatClient extends Frame{
TextField tfTxt = new TextField();
TextArea taContent = new TextArea();
public static void main(String[] args) {
new ChatClient().launchFrame();
}
public void launchFrame() {
setLocation(400, 300);
setSize(300, 300);
add(tfTxt, BorderLayout.SOUTH);
add(taContent, BorderLayout.NORTH);
// taContent.setBackground(Color.LIGHT_GRAY);
pack();
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
// TODO Auto-generated method stub
setVisible(false);
System.exit(-1);
}
});
tfTxt.addActionListener(new TFListener());
setVisible(true);
}
private class TFListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
String s = tfTxt.getText().trim();
taContent.setText(s);
tfTxt.setText("");
}
}
}
得到结果为:
Chat0.5版本: 增加了Server端,实现Sever端的基本功能。
Chat0.6版本: 在Clint端添加方法Connect(),实现和Server端建立联接的功能;并在实现ActionListener接口时添加代码,将Client端TextField中输入的内容在Server端输出;在Server端添加必要代码,接收Client端传来的数据。
这里,我将这两个版本合并在一起,称为MyChat0.2版本:
ChatServer.java为:
import java.io.*;
import java.net.*;
public class ChatServer {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(8888);
while (true) {
Socket s = ss.accept();
System.out.println("a client connected!");
DataInputStream dis = new DataInputStream(s.getInputStream());
String str = dis.readUTF();
System.out.println(str);
dis.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
ChatClient.java为:
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
public class ChatClient extends Frame{
Socket s = null;
TextField tfTxt = new TextField();
TextArea taContent = new TextArea();
public static void main(String[] args) {
new ChatClient().launchFrame();
}
public void launchFrame() {
setLocation(400, 300);
setSize(300, 300);
add(tfTxt, BorderLayout.SOUTH);
add(taContent, BorderLayout.NORTH);
// taContent.setBackground(Color.LIGHT_GRAY);
pack();
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
// TODO Auto-generated method stub
setVisible(false);
System.exit(-1);
}
});
tfTxt.addActionListener(new TFListener());
setVisible(true);
connect();
}
private void connect() {
try {
s = new Socket("127.0.0.1", 8888);
System.out.println("connected!");
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private class TFListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
String str = tfTxt.getText().trim();
taContent.setText(str);
tfTxt.setText("");
try {
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
dos.writeUTF(str);
dos.flush();
dos.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
在Client窗口输入"FIRST",运行结果为:
但是当第二次在Client窗口输入"SECOND”时,程序抛出异常,如图:
异常显示提示:Socket已经关闭,检查程序,发现在ChatClient.java里有dos.close()语句关闭了Socket,应去掉此语句。将在MyChat0.3中改进。
Chat0.7版本同0.6,嘿嘿,貌似0.6版本改太多了。。。
Chat0.8版本: 在ChatClient.java里注释掉dos.close()语句,将DataOutputStream dos变为外部类成员变量,增加disconnect()方法;在ChatServer.java里修改while(true)语句。
在这里,我将Chat0.8版本修改的内容分开,在我的MyChat0.3版本里,实现Chat0.8版本分号前的变化。在MyChat0.4版本里,实现Chat0.8版本分号后的变化:
ChatServer.java同0.2版本,ChatClient.java为:
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
public class ChatClient extends Frame{
Socket s = null;
DataOutputStream dos;
TextField tfTxt = new TextField();
TextArea taContent = new TextArea();
public static void main(String[] args) {
new ChatClient().launchFrame();
}
public void launchFrame() {
setLocation(400, 300);
setSize(300, 300);
add(tfTxt, BorderLayout.SOUTH);
add(taContent, BorderLayout.NORTH);
// taContent.setBackground(Color.LIGHT_GRAY);
pack();
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
// TODO Auto-generated method stub
setVisible(false);
disconnect();
System.exit(-1);
}
});
tfTxt.addActionListener(new TFListener());
setVisible(true);
connect();
}
private void connect() {
try {
s = new Socket("127.0.0.1", 8888);
dos = new DataOutputStream(s.getOutputStream());
System.out.println("connected!");
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void disconnect() {
try {
dos.close();
s.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private class TFListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
String str = tfTxt.getText().trim();
taContent.setText(str);
tfTxt.setText("");
try {
dos.writeUTF(str);
dos.flush();
// dos.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
最后得到结果: 解决了0.2版中Client一方不能多次输入的问题,但是在Server端出现新问题,即在Client端第二次及以后输入的数据在Server端无法显示。这是因为Server端String str = dis.readUTF();为阻塞式语句,代码会一直停在那里等待read,不能回到之前代码ServerSocket ss = new ServerSocket(8888);和DataInputStream dis = new DataInputStream(s.getInputStream());MyCaht0.4版本将通过修改while(true)的方式解决这一问题。
MyChat0.4版本ChatClient.java同0.3版本,ChatServer.java代码如下:
import java.io.*;
import java.net.*;
public class ChatServer {
public static void main(String[] args) {
boolean started = false;
try {
ServerSocket ss = new ServerSocket(8888);
started = true;
while (started) {
boolean bConnected = false;
Socket s = ss.accept();
System.out.println("a client connected!");
bConnected = true;
DataInputStream dis = new DataInputStream(s.getInputStream());
while (bConnected) {
String str = dis.readUTF();
System.out.println(str);
}
dis.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
得到结果如图:
解决了之前两个版本的小BUG。
但是,当关闭窗口时,系统会抛出如下所示的异常:
java.io.EOFException
at java.io.DataInputStream.readUnsignedShort(Unknown Source)
at java.io.DataInputStream.readUTF(Unknown Source)
at java.io.DataInputStream.readUTF(Unknown Source)
at ChatServer.main(ChatServer.java:17)
这是因为
Server端String str = dis.readUTF()语句造成的!