欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java 实现 仿QQ聊天系统 简易地实现 网络 在线聊天 代码详解(附源代码)

程序员文章站 2022-05-20 09:36:55
...

首先,实现的效果如下图:

java 实现 仿QQ聊天系统 简易地实现 网络 在线聊天 代码详解(附源代码)java 实现 仿QQ聊天系统 简易地实现 网络 在线聊天 代码详解(附源代码)

  这是一个非常经典的例题,几乎在每本程序语言入门书中都会涉及到一部分原理的讲解。我在这里简单地介绍一下代码的实现,让刚学习网络编程的读者更好的理解和实现,二来加深自己的记忆。

  这个原理无非就是 利用服务器端处理消息再返回给客户端,实现客户端之间的信息交互。 这个原理与生活息息相关,比如两部手机之间的电话交流并不是两部机器直接交流,而是通过信息发射台或者卫星来实现信息交互。虽然原理非常简单,但如果想很完整地实现这个功能并不十分容易(至少对我来讲)。

整个程序代码很简短,主要用到的 java Socket套接字、多线程知识。主要难度在于非常容易产生Exception。

下面附上服务器端代码

package chat;


import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.LinkedList;
import java.util.List;


public class ChatServer {
	public  static ServerSocket serverForClient=null;
	public static boolean bool1=false;//用来判断是否连接成功
	
	List<Client> clients=new  LinkedList<Client>();
	
	public static void main(String[] args) {
		ChatServer start=new ChatServer();
		start.runing();
		
		
	
	}
	
	
	public  void runing()  {//连接客户端,并启动线程
		 Socket serverSocket=null;//这个名字起得非常不好 和关键字SeverSocket重名了,很容易混淆,建议读者改掉,我这里懒得改了
		 try {
				serverForClient=new ServerSocket(3333);
				 bool1=true;//当服务器连接成功时 为true
				
				
				 
			} catch (IOException e1) {
				System.out.println("端口被占用,请关闭相关占用程序重启服务器!");
			}
		    try {   int count=0;
						while(bool1) {
							
							if(count==0) {
							System.out.println("*********正在等待客户端连接******");}
							
							count++;
							serverSocket =serverForClient.accept();
						System.out.println("**第"+count+"个客户端正在连接中……");
						Client cc=new Client(serverSocket);
						cc.setClient(cc);
						new Thread(cc).start();
						
						clients.add(cc);
						
						//new Thread(new Client(serverSocket)).start();
					}
						} catch (IOException e1) {
						e1.printStackTrace();
					}finally {
						try {
							serverSocket.close();
							
						} catch (IOException e) {	
						e.printStackTrace();
						}
					}

					
	}
		
class Client implements Runnable{// 启用线程类来 接受客户端
	Client me=null;
    		DataInputStream serverIn=null;
			  DataOutputStream serverOut=null;
			  Socket ss=null;
		public  String accept=null;//这里的字符串名字与accept()方法重名,容易混淆,建议改掉!
		
		public Client(Socket s ){
			  ss=s;
			  try {
				serverIn=new DataInputStream(ss.getInputStream());
			serverOut=new DataOutputStream(ss.getOutputStream());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		}


public void send(String sss)	{
	try {
		serverOut.writeUTF(sss);	
	} catch (IOException e) {
		
		e.printStackTrace();
	}
	
}
public void setClient (Client s) {
	me=s;
	
}
public void run() {
	
	try {	
		while(bool1) {//服务器端等待接受客户端的消息
			
			accept=serverIn.readUTF();
				for(int i=0;i<clients.size();i++) {//把接受到的消息发送给每一个客户端
					Client c=clients.get(i);
					if(me!=c) {
					c.send(accept+"\n");
					
					}
				}
				//System.out.println(""+accept); //这句话在代码全部完成前可以用来测试服务器是否收到客户端消息
		
		}
	}
		catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			}finally {
				try {
					if(ss!=null) ss.close();
					if(serverIn!=null) serverIn.close();
					if(serverOut!=null) serverOut.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
        }
      }
     }
   }

			

服务器端:建立一个接受 客服端连接的 ServerSocket,当有客户端连接时,得到对应的Socket,并传入给线程,线程保存每一个接入的客服端并接受客服端消息,然后发送给其他所有的客户端。(这相当于一个QQ群,当客户端接入相同的服务器IP和端口时,客户端之间即可实现群聊)

下面附上客户端代码

package chat;



import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowListener;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.swing.*;

public class ChatClient extends JFrame implements ActionListener{

	 
	 public static boolean bool1=false;//用来判断是否连接成功
	  JTextField text=new JTextField();
			JTextArea area=new JTextArea();	
			JScrollPane scroll=new JScrollPane(area);
			Socket clientSocket=null;
			DataOutputStream clientOut=null;
			 DataInputStream clientIn=null;
	public static void main(String[] args) {
		 
	new ChatClient().launchJFrame();
	
	
	}	

	public void launchJFrame() {
		this.setBounds(400, 400, 400, 400);
		this.setVisible(true);
 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		this.add(scroll,BorderLayout.CENTER);
		this.add(text,BorderLayout.SOUTH);
		text.addActionListener(this);
		connect();
		
	}

	public void connect() {
		try {
			 clientSocket=new Socket("localhost",3333);
			 bool1=true;
			 clientIn=new DataInputStream(clientSocket.getInputStream());
			clientOut=new DataOutputStream(clientSocket.getOutputStream());
			System.out.println("连接服务器成功");
			new Thread(new Receiver()).start();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
			
		
		
		
	}
	public void actionPerformed(ActionEvent arg0) {
		 String s=text.getText().trim();
		// area.setText(s);	
		 
		 try {
			clientOut.writeUTF(""+s);
			
			area.append("我发送的消息:"+s+"\n");
			clientOut.flush();
			text.setText("");	
//clientOut.close();//这里不能关闭否则没法继续向服务器端发送信息
		} catch (IOException e) {
			
			e.printStackTrace();
		}
		
	}
 class Receiver implements Runnable{//内部的类中添加线程:接受服务器消息

		
		public void run() {
			 while(bool1) {
				 try {
				String clientAccept=clientIn.readUTF();
					area.append("接收到的消息:"+clientAccept);
				} catch (IOException e) {
					try {
						if(clientIn!=null)  clientIn.close();
					} catch (IOException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
				}
			}
		}
    }
 }

客户端:客户端是一个JFrame 窗口,给文本框添加一个ActionListener监视器,将文本框内容输入到输出流中。和服务器端一样创建内部的线程,让线程去获取服务器发送到输出流中的信息并显示在文本区内。

那么客户端和服务器端写好这个程序就基本完成了,先让服务器端运行起来,之后就可以运行多个客户端。客户端将信息发送到服务器,服务器接受并把它发送到其他客户端,即可实现客户端的在线聊天。

到这里来说 功能已经实现了。但是可以预见,即使我试图使用多个catch尽可能地去抓程序中的异常,并使用finally尽量去关闭已经打开且无用的流。我的代码依然有一些问题。

 

java 实现 仿QQ聊天系统 简易地实现 网络 在线聊天 代码详解(附源代码)

 

当我关闭一个客户端的时候,服务器端会抛出SocketException异常,虽然这并不影响程序的继续运行。这个问题检查代码用点时间应该也容易解决,不过我已经失去耐心,不想再去花时间处理这种异常问题,读者如果使用我的代码可以在此基础上修改。