内容:
今天看了一个聊天室的代码,发现其中的很多内容在学控制反转,和MVC模式的时候学过了,
不过线程类没接触,
代码的原地址:
下面是阅读时在代码上加的注释:
客户端:
public class Client extends Frame{ //Frame是带有边框和标题的顶层窗口,父类是Window类;
TextField tf =new TextField(); //文本框,只有一行可写;
TextArea ta =new TextArea(); //多行输入框;
Socket s =null; //socket可以理解为一个IP地址加一个端口,客户端需要定义一个用于放送信息的socket对象;
DataOutputStream dos =null; //数据操作流,这是由于数据输出的类;
DataInputStream dis =null; //数据输入;
boolean bConnected =false; //应该是判断客户端是否与服务端相连;
recvThread r =new recvThread(); //线程类,不太清楚;
public static void main(String[] args) {
new Client().creatFrame();
}
private void creatFrame() {
this.setBounds(300, 300, 300, 300); //设置窗口大小
ta.setEditable(false); //字面意思,设置选项不可编辑;
this.add(tf, BorderLayout.SOUTH);//后面这个有点印象,是将窗口分成五个区域,这句话的意思是将一个文本框(tf)加到南部;
this.add(ta, BorderLayout.NORTH);//把ta放到client的北部;
this.addWindowListener(new WindowAdapter() { //响应关闭窗口事件,采用是事情接听器;
public void windowClosing(WindowEvent e) {
/*指示窗口发生改变的低级别事件,
当打开、关闭、激活、停用、图标化或取消图标化 Window 对象时,
或者焦点转移到 Window 内或移出 Window 时,由 Window 对象生成此低级别事件。*/
disconnect();
System.exit(0);
}
});
tf.addActionListener(new tfListener()); //响应输入事件,加一个接听器;
this.pack(); //这个pack是打包的意思?
this.setVisible(true); //可见
connect();
new Thread(r).start();
}
public void connect() {
try {
s = new Socket("127.0.0.1", 8888); //建立客户端对象
dos = new DataOutputStream(s.getOutputStream());
dis = new DataInputStream(s.getInputStream());
bConnected = true;
} catch (UnknownHostException e) { //判断是否知道主机地址
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因;
} catch (IOException e) { //判断IO流异常,且由于IO包括UnknownHost,所以必须写后面;
e.printStackTrace();
}
}
public void disconnect() { //窗口关闭时关闭客户端,输入,输出
try {
dos.close();
dis.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
class tfListener implements ActionListener { //输入框实现的接口,响应输入事件
public void actionPerformed(ActionEvent e) {
String str = tf.getText(); //获取文本框中的类
ta.setText(str); //在文本中加文本
tf.setText("");
try {
dos.writeUTF(str); //这里的UTF是unicode的UTF-8编码;
dos.flush(); //清空
dos.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
class recvThread implements Runnable { //客户端线程接收数据
public void run() {
try {
while (bConnected) {
String str;
str = dis.readUTF(); //拿到数据
ta.setText(ta.getText() + str + '\n');//显示到显示框中
}
} catch (SocketException e) { //这里一般是服务端或用户端一方主动断开连接产生的异常;
System.out.println("退出了");
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
客户端:
public class Server {
boolean started = false;
ServerSocket ss = null;
List<ChatClient> clients = new ArrayList<ChatClient>(); //保存客户端线程类
public static void main(String[] args) {
new Server().start();
}
void start() {
try {
ss = new ServerSocket(8888); //建立服务端对象
started = true;
} catch (BindException e) { //地址已在使用
System.out.println("端口使用中");
} catch (IOException e) {
e.printStackTrace();
}
try {
while (started) {
Socket s = ss.accept(); //接收客户端
ChatClient c = new ChatClient(s);
System.out.println("客戶端接收成功");
new Thread(c).start(); //启动线程
clients.add(c); //添加线程类
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
ss.close();
} catch (IOException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
}
}
class ChatClient implements Runnable { //建立客户端线程接收,发送数据
private Socket s;
DataInputStream dis = null;
DataOutputStream dos = null;
boolean bConnected = false;
public ChatClient(Socket s) {
this.s = s;
try {
dis = new DataInputStream(s.getInputStream());
dos = new DataOutputStream(s.getOutputStream());
bConnected = true;
} catch (IOException e) {
e.printStackTrace();
}
}
void send(String str) {
try {
dos.writeUTF(str);
} catch (SocketException e) {
System.out.println("對方退出了");
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
try {
while (bConnected) {
String str = dis.readUTF();
System.out.println(str);
for (int i = 0; i < clients.size(); i++) {
ChatClient c = clients.get(i);
c.send(str);
}
}
} catch (EOFException e) {
System.out.println("客戶端退出了");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (dis != null)
if (s != null)
try {
dis.close();
s.close();
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}