今天很郁闷,好久没有这种感觉了!在蓝杰弄了近一天的聊天室,下午还是决定去打篮球,放松一下!打了一场酣畅淋漓的全场比赛,最终打平了,结果不是最希望看到的,但是期间的努力却是集体7个人共同努力的结果,跟在蓝杰一样,需要通力合作,无奈我还算低调,有什么问题,轻易不会问别人,这大概是在小时候留下的病根!令人欣慰的是,打完球回来之后,并没有首先洗澡,而是又把我的聊天室代码琢磨了一遍,伴随着汗臭味,一切阻碍就这么豁然开朗了,这也算是做学问吧!也许有的时候,我们需要的只是一个好心情,一个好的心态!!!!
现在我的小小聊天室,具体分析如下:
首先我们需要先写一个服务器的界面类,在这个类里面,主要有创建服务器和发送服务器消息两个按钮,而服务器的功能有能将所有客户端的消息发给每一个在线用户,也可以在服务器的界面显示每一个客户端的发送的消息。该界面类创建代码如下
package 多人聊天室;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class MainServer {
public void ShowUI(){
JFrame jf=new JFrame();
jf.setTitle("多人聊天室");
jf.setSize(600,500);
jf.setLayout(new FlowLayout());
jf.setDefaultCloseOperation(3);
JButton jb=new JButton("创建");
final JTextField jte=new JTextField(4);
JButton jb1=new JButton("发送");
final JTextField jte1=new JTextField(30);
final JTextArea jta=new JTextArea(20,50);
jf.add(jb);
jf.add(jte);
jf.add(jb1);
jf.add(jte1);
jf.add(jta);
ActionListener al=(new ActionListener(){
public void actionPerformed(ActionEvent e){
String s=e.getActionCommand();
if(s.equals("创建")){
String ss=jte.getText();
int i=Integer.parseInt(ss);
Chatserver cs=new Chatserver(i,jta);
cs.start();
}
//将服务器消息发给每个人
if(s.equals("发送")){
String msg=jte1.getText();
ChatTools.castMsg(msg);
jta.append("服务器说:"+msg+"\r\n");
jte1.setText("");
}
}
});
jb.addActionListener(al);
jb1.addActionListener(al);
jf.setVisible(true);
}
public static void main(String[] args){
MainServer ms=new MainServer();
ms.ShowUI();
}
}
在该监听器中我使用的是内部类,在创建按钮后的 TextFiel 中输入端口号后,当该按钮被点击时,指定端口号的服务器启动了,此时服务器在等待客户机的连接,当有客户机连接了服务器之后,我们必须启动一个线程去处理该客户机对象,否则就如同一部普通手机一般,如果此时你正在通话中,那么别人是不可能在打通你的电话的,所以我们要创建一个线程类来处理连接上服务器的客户机线程对象。代码如下:
package 多人聊天室;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JTextArea;
public class Chatserver extends Thread{
private boolean running=true;
private int port;
private JTextArea jta;
public Chatserver(int port,JTextArea jta){
this.port=port;
this.jta=jta;
}
public void run(){
setUpServer(port);
}
//在指定端口上创建一个服务器
public void setUpServer(int port){
try{
//建立绑定在指定端口上的服务器对象
ServerSocket ss=new ServerSocket(port);
System.out.println("服务器创建成功");
//等待客户机连接,并设置成循环等待状态
while(running){
Socket client=ss.accept();
System.out.println("欢迎进入我的服务器");
//启动一个线程去处理该对象
ServerThread st=new ServerThread(client,jta);
st.start();
ChatTools.add(st);
}
}catch(Exception ef){
ef.printStackTrace();
}
}
}
而每一个客户端在服务器中都会拥有一个相应的处理客户端链接的方法,所以我有创建了一个线程类,在该类中得到了服务器的Socket的输入输出流。构造了一个该类的方法,用于传值;又定义了客户机一旦进入服务器的处理方法,在该方法中我们可以读取客户机发来的消息,并将该消息,群发给每一个在线的用户,还可以群发服务器自己的消息,然后并将该方法放在线程的run方法中即可。具体代码如下:
package 多人聊天室;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import javax.swing.JTextArea;
public class ServerThread extends Thread{
private Socket client;//线程中处理的客户对象
private OutputStream out;//输出流
private JTextArea jta;
//创建线程对象时要传入他要处理的连接对象
public ServerThread(Socket client,JTextArea jta){
this.client=client;
this.jta=jta;
}
// //将发送消息的代码包装到一个方法中
// public void sendMs(String msg){
// System.out.println("send--->"+msg);
// try{
// msg+="\r\n";
// out.write(msg.getBytes());
// //强制输出
// out.flush();
// }catch(Exception ef){}
//}
public void run(){
//在线程中 调用处理链接的方法
processChat(this.client);
}
//处理客户机进入的连接对象
public void processChat(Socket client){
try{
InputStream ins=client.getInputStream();
out=client.getOutputStream();
//将输入流装为可以读一行字符串,也就是以\r\n结尾的字符串
out.write( ("欢迎进入服务器\r\n").getBytes() );
BufferedReader brd=new BufferedReader(new InputStreamReader(ins));
String input=brd.readLine();//一行一行读取客户机发来的消息
while(!"bye".equals(input)){
System.out.println("服务器收到的是"+input);
jta.append("客户说:"+input+"\r\n");
//读到一条消息就把他发给其他客户机
ChatTools.castMsg(input);
input=brd.readLine();//读取下一条
}
}catch(Exception ef){
ef.printStackTrace();
}
}
}
而为了能实现消息群发的功能,并且获取当前在线的人数,我还建了一个类,在类中引用java提供的队列,当每进入一个客户机时,我们便将该客户机存入队列中,并且输出当前的在线人数,并在之后定义了一个消息群发的功能!代码如下
package 多人聊天室;
import java.util.ArrayList;
import java.util.List;
public class ChatTools {
//保存处理线程的队列对象
private static List<ServerThread> list=new ArrayList();
private ChatTools(){
}//不需要创建引类对象,构造器则私有
//取得保存保存处理线程对象的队列
public static List<ServerThread> getAllthread(){
return list;
}
//将一个客户对应的处理线程对象加入到队列中
public static void add(ServerThread st){
//通知有人上线了
castMsg("我在线上!!目前在线人数"+(list.size()+1));
list.add(st);
}
//将一个消息发送给所有人
public static void castMsg(String str){
for(int i=0;i<list.size();i++){
ServerThread st=list.get(i);
st.sendMs(i+"说:"+str);
}
}
}
这样一来,创建服务器并简单实现界面化的工作便完成,接下来我们还要给客户端也实现相应功能和界面化。
无可厚非,我们需要先写一个界面类。该界面能实现对服务器的连接以及将自己写的消息发送给服务器,再由服务器转发给所有在线的用户。代码如下:
package 多人聊天室客户端;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import 多人聊天室.MainServer;
public class Mainchat {
private MainchatThread mt;
public void ShowUI(){
JFrame jf=new JFrame();
jf.setTitle("客户端");
jf.setSize(500,500);
jf.setLocation(400, 300);
jf.setLayout(new FlowLayout());
jf.setDefaultCloseOperation(3);
JButton jb=new JButton("连接服务器");
JButton jb1=new JButton("发送");
final JTextField jte1=new JTextField(30);
final JTextArea jta=new JTextArea(20,40);
jf.add(jb);
jf.add(jb1);
jf.add(jte1);
jf.add(jta);
ActionListener al=(new ActionListener(){
public void actionPerformed(ActionEvent e){
String s=e.getActionCommand();
if(s.equals("连接服务器")){
try {
mt=new MainchatThread("localhost",9090,jta);
if(mt.runing()){
mt.start();
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
//将消息发给别人
if(s.equals("发送")){
String msg=jte1.getText();
jta.append("我说:"+msg+"\r\n");
mt.sendMsg(msg);
jte1.setText("");
}
}
});
jb.addActionListener(al);
jb1.addActionListener(al);
jf.setVisible(true);
}
public static void main(String[] args){
Mainchat ms=new Mainchat();
ms.ShowUI();
}
}
另外,同样我们也需要定义一个线程,来读取从服务器获得消息,当我们的客户端连接成功后,而在该类中我还定义了读取的方法,并将其输出在界面上,具体代码如下:
package 多人聊天室客户端;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.JTextArea;
public class MainchatThread extends Thread{
private OutputStream out;
private BufferedReader brd;
private Socket socket;
private int port;
private String ip;
private JTextArea jta;
public MainchatThread(String ip,int port,JTextArea jta){
this.jta=jta;
this.ip=ip;
this.port=port;
}
public boolean runing(){
try{
Socket socket=new Socket(this.ip,this.port);
System.out.println("连接成功");
InputStream ins =socket.getInputStream();//得到输入输出流对象
out=socket.getOutputStream();
brd=new BufferedReader(new InputStreamReader(ins));//读取一行字符串
return true;
}catch (Exception e){
e.printStackTrace();
}return false;
}
//读取服务端信息的方法
public void readMsg(){
try{
String input=brd.readLine();
while(!"bye".equals(input)){
System.out.println("服务器"+input);
jta.append(input +"\r\n");
System.out.println("你好");
input=brd.readLine();
}
}catch(Exception ef){}
}
//输出信息
public void sendMsg(String msg){
try{
msg+="\r\n";
this.out.write(msg.getBytes());
this.out.flush();
}catch(Exception ef){}
}
public void run(){
readMsg();
}
}
至此,简单聊天室告了一个小段落,其实还是拥有很多值得改进的地方,比如,如何将所有用户显示在服务器上,并且能实现单独对话和删除用户的功能,当然还有客户端的登陆功能,这些事情在大的框架形成之后,想必不是难事。
今天的事,从一个方面反应了,其实并不是差在哪里,只是差在心态,当然时间也是一个很重要的不分,所谓勤能补拙,更何况我们都自认不是拙人,当然别人更不是拙人,心态和勤奋确实是两个很重要的因素,记之!!!!!!