基于GUI的简单聊天室02

服务器端

与上一篇相比,加进了线程内部类,解决多个客户端连接时,服务器无法全部响应的问题。

利用List集合来装载客户端的对象。

还需要注意全局变量的应用。

 /**
* 相比01,加进了线程内部类,解决多个客户端连接时,服务器无法全部响应的问题。
* @author Administrator
*
*/ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List; public class ChatSever02 {
// 布尔类型变量表示服务器是否开着
boolean started = false; ServerSocket ss = null; List<Client> clients = new ArrayList<Client>(); public static void main(String[] args) {
new ChatSever02().start();
} public void start() {
try {
// 建立服务端,8888为端口号
ss = new ServerSocket(8888);
started = true;
}
catch (BindException e) {
System.out.println("Socket has been used !");
System.out.println("请重启服务器 !");
System.exit(0);
}catch (IOException e) {
e.printStackTrace();
}
// 服务器开启后,started变为true
try {
// 接受客户端的连接
while (started) {
Socket s = ss.accept();
//构造Client对象
Client c = new Client(s);
clients.add(c);
System.out.println("一个客户连接");
//启动线程
new Thread(c).start();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} /**
* 建立线程内部类
*/
class Client implements Runnable{ //要保有自己的Socket属性
private Socket s = null; //自己的数据输入流
private DataInputStream dis = null; private DataOutputStream dos = null; private boolean bConnected = false ; //采用构造方法,把Socket属性传进来
public Client(Socket s) {
//赋值给s
this.s = s ;
//将dis初始化
try {
dis = new DataInputStream(s.getInputStream());
dos = new DataOutputStream(s.getOutputStream());
//连接成功后,bConnected 变为true
bConnected = true ;
} catch (IOException e) {
e.printStackTrace();
}
} /**
* 发送信息的方法
*/
public void send(String str) {
try {
dos.writeUTF(str);
System.out.println(str);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
//while循环范围过大, 导致过一直报错;
while (bConnected) {
String str = dis.readUTF ();
//System.out.println(str);
//发送信息
for(int i = 0;i < clients.size(); i++) {
Client c = clients.get(i);
c.send(str);
//System.out.println(str);
} /*利用迭代器
for(Iterator it = clients.iterator();it.hasNext();) {
Client c = it.next();
c.send(str);
}
*/
/*利用迭代器第二版本
Iterator<Client> it = clients.iterator();
while(it.hasNext()) {
Client c = it.next();
c.send(str);
}
*/
}
}catch (EOFException e) { System.out.println("Client Close !");
}catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(dis != null) dis.close(); //再设置dis = null;
if(dos != null) dis.close();
if(s != null) s.close();
} catch (IOException e) {
e.printStackTrace();
}
} }
}
}

客户端也只是多了线程类来接收信息

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException; import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField; /**
* 完成图形界面
* @author Administrator
*
*/
public class ChatClient extends JFrame{
JTextField jTextField = new JTextField(); JTextArea jTextArea = new JTextArea(); Socket s;
//表示是否连上
private boolean bConnected = false; DataOutputStream dos; DataInputStream dis = null; public static void main(String[] args) {
new ChatClient().launchFrame();
} public void launchFrame() {
setLocation(200, 150);
this.setSize(450, 450);
this.add(jTextArea,BorderLayout.NORTH);
this.add(jTextField,BorderLayout.SOUTH);
jTextField.addActionListener(new TFListener());
//pack();
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent arg0) {
disConnect();
System.exit(0);
}
});; setVisible(true);
connect();
new Thread(new RecvThread()).start();
} /**
* 建立连接的方法
* @throws IOException
* @throws UnknownHostException
*/
public void connect() {
try {
s = new Socket("127.0.0.1",8888);
//连接好后初始化
dos = new DataOutputStream(s.getOutputStream());
dis = new DataInputStream(s.getInputStream());
System.out.println("连接成功");
bConnected = true;
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 断开连接,关闭资源的方法
*/
public void disConnect() {
try {
dos.close();
dis.close();
s.close();
} catch (IOException e1) {
e1.printStackTrace();
} } /**
* 内部类,实现监听
* 将文本框中的输入打印到文本域中
*
*/ private class TFListener implements ActionListener{ @Override
public void actionPerformed(ActionEvent e) {
String content = jTextField.getText().trim();
//jTextArea.setText(content);
jTextField.setText("");
//将文本发送到服务器
try {
//System.out.println(s);
System.out.println(content);
dos.writeUTF(content);
dos.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
} } /**
* 线程类,用于接受信息
*
*/
private class RecvThread implements Runnable{ @Override
public void run() {
try {
while(bConnected) {
String str = dis.readUTF();
//System.out.println(str);
jTextArea.setText(jTextArea.getText() + str +" ");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
上一篇:Android 获得图片并解码成缩略图以减少内存消耗


下一篇:three.js 第二篇:场景 相机 渲染器 物体之间的关系