java聊天室源代码(练习项目)

聊天室界面如下:

java聊天室源代码(练习项目)_第1张图片

java聊天室源代码(练习项目)_第2张图片

聊天室源代码链接

一、服务端:

窗体:

package sonyi.server;


import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;

public class WindowServer {
	public static JFrame window;
	public static JTextArea textMessage;//聊天记录
	public static JList user;//用户列表
	public static int ports;
	JButton start,send,exit;
	JTextField portServer,message,name;
	
	//主函数入口
	public static void main(String[] args) {
		new WindowServer();
	}

	//初始化窗体
	public WindowServer() {
		init();
	}
	
	//初始化内容
	public void init(){//采用绝对布局
		window = new JFrame("服务端");
		window.setLayout(null);
		window.setBounds(200, 200, 500, 400);
		window.setResizable(false);//不可改变大小
		
		JLabel label1 = new JLabel("端口号:");
		label1.setBounds(10, 8, 50, 30);
		window.add(label1);
		
		portServer = new JTextField();
		portServer.setBounds(60, 8, 100, 30);
		portServer.setText("30000");
		window.add(portServer);
		
		JLabel names = new JLabel("用户名:");
		names.setBounds(180, 8, 55, 30);
		window.add(names);
		
		name = new JTextField();
		name.setBounds(230, 8, 60, 30);
		name.setText("服务端");
		window.add(name);
		
		start = new JButton("启动");
		start.setBounds(300, 8, 80, 30);
		window.add(start);
		
		exit = new JButton("关闭");
		exit.setBounds(390, 8, 80, 30);
		window.add(exit);
		
		
		JLabel label2 = new JLabel("用户列表");
		label2.setBounds(40, 40, 80, 30);
		window.add(label2);
		
		
		user = new JList();
		JScrollPane scrollPane = new JScrollPane(user);//添加滚动条
		scrollPane.setBounds(10, 70, 120, 220);
		window.add(scrollPane);
		
		textMessage = new JTextArea();
		textMessage.setBounds(135, 70, 340, 220);
		textMessage.setBorder(new TitledBorder("聊天记录"));//设置标题
		textMessage.setEditable(false);//不可编辑
		//文本内容换行的两个需要配合着用
		textMessage.setLineWrap(true);//设置文本内容自动换行,在超出文本区域时,可能会切断单词
		textMessage.setWrapStyleWord(true);//设置以自动换行,以单词为整体,保证单词不会被切断
		JScrollPane scrollPane1 = new JScrollPane(textMessage);//设置滚动条
		scrollPane1.setBounds(135, 70, 340, 220);
		window.add(scrollPane1);
		
		message = new JTextField();
		message.setBounds(10, 300, 360, 50);
		
		window.add(message);
		
		send = new JButton("发送");
		send.setBounds(380, 305, 70, 40);
		window.add(send);
		
		myEvent();	//添加监听事件
		window.setVisible(true);
	}
	
	public void myEvent(){
		window.addWindowListener(new WindowAdapter() {//关闭窗体
			public void windowClosing(WindowEvent e){
				//如果有客户端存在,发信息给客户端,并退出
				if(StartServer.userList != null && StartServer.userList.size() != 0){
					try {
						new SendServer(StartServer.userList, "" , "4");//4代表服务端退出
					} catch (IOException e1) {
						e1.printStackTrace();
					}
				}
				System.exit(0);//退出窗体
			}
		});
		
		exit.addActionListener(new ActionListener() {	//退出连接
			public void actionPerformed(ActionEvent e) {
				if(StartServer.ss == null || StartServer.ss.isClosed()){//如果已退出,弹窗提醒
					JOptionPane.showMessageDialog(window, "服务器已关闭");
				}else {
					//发信息告诉客户端,要退出
					if(StartServer.userList != null && StartServer.userList.size() != 0){
						try {
							new SendServer(StartServer.userList, "" , 4 + "");	
						} catch (IOException e1) {
							e1.printStackTrace();
						}
					}
					try {
						start.setText("启动");
						exit.setText("已关闭");
						StartServer.ss.close();//关闭服务端
						StartServer.ss = null;
						StartServer.userList = null;
						StartServer.flag = false;//改变服务端循环标记
					} catch (IOException e1) {
						e1.printStackTrace();
					}
				}	
			}
		});
		
		//开启服务端
		start.addActionListener(new ActionListener() {		
			public void actionPerformed(ActionEvent e) {
				//如果服务端已经开启,弹窗提醒服务端已开启
				if(StartServer.ss != null && !StartServer.ss.isClosed()){
					JOptionPane.showMessageDialog(window, "服务器已经启动");
				}else {
					ports = getPort();//获取端口号
					if(ports != 0){
						try {
							StartServer.flag = true;//改变服务端接收循环标记
							new Thread(new StartServer(ports)).start(); //开启服务端接收线程
							start.setText("已启动");
							exit.setText("关闭");
						} catch (IOException e1) {
							JOptionPane.showMessageDialog(window, "启动失败");
						}
					}
				}
			}
		});
		
		//点击按钮发送消息
		send.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				sendMsg();
			}
		});
		
		//按回车发送消息
		message.addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent e) {
				if(e.getKeyCode() == KeyEvent.VK_ENTER){
					sendMsg();
				}
			}
		});
	}
	
	//发送消息方法
	public void sendMsg(){
		String messages = message.getText();
		//判断内容是否为空
		if("".equals(messages)){
			JOptionPane.showMessageDialog(window, "内容不能为空!");
		}else if(StartServer.userList == null || StartServer.userList.size() == 0){//判断是否已经连接成功
			JOptionPane.showMessageDialog(window, "未连接成功,不能发送消息!");
		}else {
			try {
				//将信息发送给所有客户端
				new SendServer(StartServer.userList, getName() + ":" + messages, 1 + "");
				//将信息添加到客户端聊天记录中
				WindowServer.textMessage.append(getName() + ":" + messages + "\r\n");
				message.setText(null);//消息框设置为空
			} catch (IOException e1) {
				JOptionPane.showMessageDialog(window, "发送失败!");
			}
		}
	}
	
	//获取端口号
	public int getPort(){
		String port = portServer.getText();
		if("".equals(port)){//判断端口号是否为空
			JOptionPane.showMessageDialog(window, "端口号为口");
			return 0;
		}else {
			return Integer.parseInt(port);//返回整形的端口号
		}	
	}	
	
	//获取服务端名称
	public String getName(){
		return name.getText();
	}
}

发送接收线程:

package sonyi.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Vector;

import javax.swing.JOptionPane;

//启动服务端接收客户端的线程
public class StartServer implements Runnable{
	private int port;
	public static ArrayList userList = null;
	public static Vector userName = null;
	public static ServerSocket ss = null;
	public static boolean flag = true;
	
	//传入端口号
	public StartServer(int port) throws IOException{
		this.port = port;		
	}

	public void run() {
		Socket s = null;
		userList = new ArrayList();//客户端端口容器
		userName = new Vector();//用户名称容器
		//System.out.println("启动服务端");
		try {
			ss = new ServerSocket(port);//启动服务端
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		while (flag) {//开启循环,等待接收客户端
			try {	
				s = ss.accept();//接收客户端
				userList.add(s);//将客户端的socket添加到容器中
				
				//打印客户端信息
				String id = s.getInetAddress().getHostName();
				System.out.println(id + "-----------connected");
				System.out.println("当前客户端个数为:" + userList.size());
				
				//启动与客户端相对应的信息接收线程
				new Thread(new ReceiveServer(s,userList,userName)).start();
		
			} catch (IOException e) {
				JOptionPane.showMessageDialog(WindowServer.window, "服务端退出!");
			}	
		}
	}
}

//服务端信息接收线程
class ReceiveServer implements Runnable{
	private Socket socket;
	private ArrayList userList;
	private Vector userName;
	
	public ReceiveServer(Socket s,ArrayList userList,Vector userName) {
		this.socket = s;
		this.userList = userList;
		this.userName = userName;
	}
	
	public void run() {	
		try {
			//读取信息流
			BufferedReader brIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			while(true){		
				char info = (char)brIn.read();//先读取信息流的首字符,并判断信息类型
				String line = brIn.readLine();//读取信息流的信息内容
				
				if(info == '1'){//1代表收到的是信息
					WindowServer.textMessage.append(line + "\r\n");//将信息添加到服务端聊天记录中
					//设置消息显示最新一行,也就是滚动条出现在末尾,显示最新一条输入的信息
					WindowServer.textMessage.setCaretPosition(WindowServer.textMessage.getText().length());
					new SendServer(userList, line, "1");//将信息转发给客户端
				}
				
				if(info == '2'){//2代表有新客户端建立连接
					userName.add(line);//将新客户端用户名添加到容器中
					WindowServer.user.setListData(userName);//更新服务端用户列表
					new SendServer(userList, userName, "2");//将用户列表以字符串的形式发给客户端
				}
				
				if(info == '3'){//3代表有用户端退出连接
					userName.remove(line);//移除容器中已退出的客户端用户名
					userList.remove(socket);//移除容器中已退出的客户端的socket
					WindowServer.user.setListData(userName);//更新服务端用户列表
					new SendServer(userList, userName, "3");//将用户列表以字符串的形式发给客户端
					socket.close();//关闭该客户端的socket
					break;//结束该客户端对于的信息接收线程
				}
			}	
		} catch (IOException e) {
			e.printStackTrace();
		}
	}	
}

//服务端发送信息
class SendServer {
	SendServer(ArrayList userList,Object message,String info) throws IOException{
		String messages = info + message;//添加信息头标记
		PrintWriter pwOut = null;
		for(Socket s : userList){//将信息发送给每个客户端
			pwOut = new PrintWriter(s.getOutputStream(),true);
			pwOut.println(messages);
		}
	}
}	

二、客户端:

窗体:

package sonyi.client;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.Socket;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;

public class WindowClient {
	JTextField port,name,ip,message;
	JButton send;
	public static JFrame window;
	public static JButton link,exit;
	public static JTextArea textMessage;
	public static Socket socket = null;
	public static JList user;
	
	//主函数入口
	public static void main(String[] args) {
		new WindowClient();
	}
	
	//初始化窗体
	public WindowClient() {
		init();
	}
	
	//窗体初始化内容
	public void init(){//采用绝对布局
		window = new JFrame("客户端");
		window.setLayout(null);
		window.setBounds(200, 200, 500, 400);
		window.setResizable(false);
		
		JLabel label = new JLabel("主机IP:");
		label.setBounds(10, 8, 50, 30);
		window.add(label);
		
		ip = new JTextField();
		ip.setBounds(55, 8, 60, 30);
		ip.setText("127.0.0.1");
		window.add(ip);
		
		
		JLabel label1 = new JLabel("端口号:");
		label1.setBounds(125, 8, 50, 30);
		window.add(label1);
		
		port = new JTextField();
		port.setBounds(170, 8, 40, 30);
		port.setText("30000");
		window.add(port);
		
		JLabel names = new JLabel("用户名:");
		names.setBounds(220, 8, 55, 30);
		window.add(names);
		
		name = new JTextField();
		name.setBounds(265, 8, 60, 30);
		name.setText("客户端1");
		window.add(name);
		
		link = new JButton("连接");
		link.setBounds(335, 8, 75, 30);
		window.add(link);
		
		exit = new JButton("退出");
		exit.setBounds(415, 8, 75, 30);
		window.add(exit);
		
		JLabel label2 = new JLabel("用户列表");
		label2.setBounds(40, 40, 80, 30);
		window.add(label2);
		
		user = new JList();
		JScrollPane scrollPane = new JScrollPane(user);//设置滚动条
		scrollPane.setBounds(10, 70, 120, 220);
		window.add(scrollPane);
		
		textMessage = new JTextArea();
		textMessage.setBounds(135, 70, 340, 220);
		textMessage.setEditable(false);//文本不可编辑
		textMessage.setBorder(new TitledBorder("聊天记录"));//设置标题
		//文本内容换行的两个需要配合着用
		textMessage.setLineWrap(true);//设置文本内容自动换行,在超出文本区域时,可能会切断单词
		textMessage.setWrapStyleWord(true);//设置以自动换行,以单词为整体,保证单词不会被切断
		JScrollPane scrollPane1 = new JScrollPane(textMessage);//设置滚动条
		scrollPane1.setBounds(135, 70, 340, 220);
		window.add(scrollPane1);
		
		message = new JTextField();
		message.setBounds(10, 300, 360, 50);
		message.setText(null);
		window.add(message);
		
		send = new JButton("发送");
		send.setBounds(380, 305, 70, 40);
		window.add(send);
		
		myEvent();//添加监听事件
		window.setVisible(true);//设置窗体可见	
	}
	
	
	public void myEvent(){//事件监听
		window.addWindowListener(new WindowAdapter() {//退出窗体
			public void windowClosing(WindowEvent e){
				//如果仍在连接,发信息给服务端,并退出
				if(socket != null && socket.isConnected()){
					try {
						new SendClient(socket, getName(), 3 + "");
					} catch (IOException e1) {
						e1.printStackTrace();
					}
				}
				System.exit(0);
			}
		});
		
		//关闭连接
		exit.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				//如果仍在连接,将信息发给服务端
				if(socket == null){
					JOptionPane.showMessageDialog(window, "已关闭连接");
				}else if(socket != null && socket.isConnected()){
					try {
						new SendClient(socket, getName(), "3");//发送信息给服务端
						link.setText("连接");
						exit.setText("已退出");
						socket.close();//关闭socket
						socket = null;
					} catch (IOException e1) {
						e1.printStackTrace();
					}
				}
			}
		});
		
		//建立连接
		link.addActionListener(new ActionListener() {		
			public void actionPerformed(ActionEvent e) {
				//判断是否已经连接成功
				if(socket != null && socket.isConnected()){	
					JOptionPane.showMessageDialog(window, "已经连接成功!");
				}else {
					String ipString = ip.getText();//获取ip地址
					String portClinet = port.getText();//获取端口号
					
					if("".equals(ipString) || "".equals(portClinet)){//判断获取内容是否为空
						JOptionPane.showMessageDialog(window, "ip或端口号为空!");
					}else {
						try {
							int ports = Integer.parseInt(portClinet);//将端口号转为整形
							socket = new Socket(ipString,ports);//建立连接
							link.setText("已连接");//更改button显示信息
							exit.setText("退出");
							new SendClient(socket, getName(), 2 + "");//发送该客户端名称至服务器
							new Thread(new ReceiveClient(socket)).start();//启动接收线程
						} catch (Exception e2) {
							JOptionPane.showMessageDialog(window, "连接未成功!可能是ip或端口号格式不对,或服务器未开启。");
						}
					}
				}
			}
		});
		
		//点击按钮发送信息
		send.addActionListener(new ActionListener() {			
			public void actionPerformed(ActionEvent e) {
				sendMsg();
			}
		});	
		
		//按回车发送信息
		message.addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent e) {
				if(e.getKeyCode() == KeyEvent.VK_ENTER){
					sendMsg();
				}
			}
		});
	}
	
	//发送信息的方法
	public void sendMsg(){
		String messages = message.getText();//获取文本框内容
		if("".equals(messages)){//判断信息是否为空
			JOptionPane.showMessageDialog(window, "内容不能为空!");
		}
		else if(socket == null || !socket.isConnected()){//判断是否已经连接成功
			JOptionPane.showMessageDialog(window, "未连接成功,不能发送消息!");
		}else {
			try {
				//发送信息
				new SendClient(socket,getName() + ":" + messages,"1");
				message.setText(null);//文本框内容设置为空
			} catch (IOException e1) {
				JOptionPane.showMessageDialog(window, "信息发送失败!");
			}
		}	
	}
	
	//获取客户端名称
	public String getName(){
		return name.getText();
	}
}

发送接收线程:

package sonyi.client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.swing.JOptionPane;

//启动客户端接收线程
public class StartClient {
	public StartClient(Socket s) throws UnknownHostException, IOException{	
		new Thread(new ReceiveClient(s)).start();
	}
}

//客户端接收线程
class ReceiveClient implements Runnable{
	private Socket s;
	public ReceiveClient(Socket s) {
		this.s = s;
	}
	public void run() {
		try {
			//信息接收流
			BufferedReader brIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
			while(true){	
				char info = (char)brIn.read();//读取信息流首字符,判断信息类型
				String line = brIn.readLine();//读取信息流内容
				
				if(info == '1'){//代表发送的是消息
					WindowClient.textMessage.append(line + "\r\n");	//将消息添加到文本域中
					//设置消息显示最新一行,也就是滚动条出现在末尾,显示最新一条输入的信息
					WindowClient.textMessage.setCaretPosition(WindowClient.textMessage.getText().length());
				}
				
				if(info == '2' || info == '3'){//有新用户加入或退出,2为加入,3为退出
					String sub = line.substring(1, line.length()-1);
					String[] data = sub.split(",");
					WindowClient.user.clearSelection();
					WindowClient.user.setListData(data);
				}
				
				if(info == '4'){//4代表服务端退出
					WindowClient.link.setText("连接");
					WindowClient.exit.setText("已退出");
					WindowClient.socket.close();
					WindowClient.socket = null;
					break;
				}
			}	
		} catch (IOException e) {
			JOptionPane.showMessageDialog(WindowClient.window, "客户端已退出连接");
		}
	}	
}

//客户端发送信息类
class SendClient {
	SendClient(Socket s,Object message,String info) throws IOException{	
		String messages = info + message;
		PrintWriter pwOut = new PrintWriter(s.getOutputStream(),true);
		pwOut.println(messages);
	}
}	

运行过程中应该还有很多bug,希望码友们指正,互相交流。



你可能感兴趣的:(lessonForJava)