Java实战项目(一)---编写聊天室程序

刚开始学java,参考《java从入门到精通》这本书,学到网络程序设计基础这一章节,尤其与其他计算机进行通信,觉得还挺有意思的。所有深入地试试做一个小程序—聊天室程序,在代码中加入我自己的理解和困惑,希望能和大家一起探讨,每行的代码基本都有注释,方便大家理解。
编译环境:eclipse(代码可以直接运行)
以下设计到的关于java的主要知识:Swing、多线程、I/O输入输出、TCP

TCP原理基础

TCP网络程序设计是指利用Socket类编写通信程序。利用TCP协议进行通信的两个应用程序是有主次之分的,一个称为服务器程序,另一个成为客户端程序,两者的功能和编写方法大不一样。
服务器端和客户端的交互过程如下图1所示:

服务器端和客户端的交互过程

  1. 服务器程序创建一个ServerSocket(服务器套接字),调用accept()方法等待客户机连接。
  2. 客户端程序创建一个Socket,请求与服务器建立连接。
  3. 服务器接受客户机的连接请求,同时创建一个新的Socket与客户建立联系。随后服务器继续等待新的请求。

流程图

服务器段程序

//服务器端程序
import java.awt.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.List;

import javax.swing.*;

public class TCPServer extends JFrame {
	
	private static final long serialVersionUID = 1L;
	private ServerSocket ss = null;    // 创建服务器套接字接口
	private boolean bStart = false;    // 添加用户标志
	
	private JTextArea taContent = new JTextArea();  // 文本域
	
	private int index = 0;     // 用户个数
	
	List<Client> clients = new ArrayList<Client>();   // 泛型--创建List集合(ArrayList是List的子类)--存储客户数
	
	// 窗口布局                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
	public void launchFrame() {
//		Container con = this.getContentPane();
		taContent.setEditable(false);    // 不可编辑
		
		taContent.setBackground(Color.DARK_GRAY);	// 背景颜色
		taContent.setForeground(Color.YELLOW);		// 文字颜色
		this.add(taContent);		 // 容器中添加文本域
		this.setSize(300, 350);		 // 设置大小
		this.setLocation(400, 200);	
		this.setTitle("TCP Server");
		this.setVisible(true);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		tcpMonitor();
	}
	
	// TCP监听
	public void tcpMonitor() {
		try {
			ss = new ServerSocket(8888);   // 服务器套接字8888
			bStart = true;    
		} catch (IOException e) {
			
			e.printStackTrace();
		}
		
		try {
			while (bStart) {
				index++;		// index代表人数
				Socket s = ss.accept();    // 等待客户端连接
				Client c = new Client(s);  // 实例化对象--用户
				clients.add(c);
				
				// getInetAddress()--返回此服务器套接字的本地地址
				// getHostAddress()--获取IP地址
				// taContent---文本域
				taContent.append(s.getInetAddress().getHostAddress()   // 文本域添加字--127.0.0.1 connect 1 clients
						+ " connected " + index + " clients\n");
				// public Thread(String threadName)-----创建一个名称为threadName的线程对象
				new Thread(c).start();			// 启动多线程
				
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				ss.close();     // 关闭套接字
			} catch (IOException e) {
				
				e.printStackTrace();
			}
		}
		
	}
	
	public static void main(String args[]) {
		TCPServer ts = new TCPServer();    // 实例化TCP网络程序
		ts.launchFrame();     // 实现窗口布局、网络连接
	}
	
	private class Client implements Runnable {
		DataInputStream dis = null;    // 数据输入流
		DataOutputStream dos = null;   // 数据输出流
		
		Socket s = null;     // 服务器接受客户端的连接请求,同时创建一个新的套接字与客户端建立连接
		boolean bStart = false;  // 添加用户标志
		
		Client(Socket s) {
			this.s = s;
			try {
				dis = new DataInputStream(s.getInputStream());   // 获取输入数据
				dos = new DataOutputStream(s.getOutputStream());	// 获取输出数据
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			bStart = true;
		}
		
		// 发送数据
		public void sendToEveryClient(String str) {
			try {
				dos.writeUTF(str);	// 输出数据----writeUTF()写出一个UTF-8编码的字符串前面会加上2个字节的长度标识
				dos.flush();    // 刷新
				
			} catch (IOException e) {
				index--;       // 用户数减少
				clients.remove(this);      // 从数组中去除该用户
				taContent.append(s.getInetAddress().getHostAddress()  // Socket s = null
						+ " exited " + index + " clients\n");
				System.out.println("对方退出了!我从List里面去掉了!");
			}
		}
		
		public void run() {
			try {
				while (bStart) {       // 当bStart=true时,读取数据
					String str = dis.readUTF();   // 读取数据
					System.out.println(str);     // 打印信息
					// 发送客户的信息
					for (int i = 0; i < clients.size(); i++) {
						Client c = clients.get(i);   // clients数组中的元素都是Client类的
						c.sendToEveryClient(str);    // 发送信息
					}
				}
			} catch (EOFException e) {
				clients.remove(this);
				taContent.append(s.getInetAddress().getHostAddress()
						+ " exited " + clients.size() + " clients\n");
				System.out.println("client closed");
			} catch (SocketException e) {
				System.out.println("client closed");
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					if (s != null)
						s.close();
					if (dis != null)
						dis.close();
					if (dos != null)
						dos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
	}
	
}

客户端程序

// 客户端程序
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;

import javax.swing.*;

public class TCPClient extends JFrame {
	private static final long serialVersionUID = 1L;
	TextArea taContent = new TextArea(); // 文本域
	JTextField tfTxt = new JTextField(20); // 文本框

	JButton send = new JButton("发送"); // 按钮
	JButton connect = new JButton("连接");
	JButton clear = new JButton("清空");

	boolean live = false;
	JPanel p1 = new JPanel();
	JPanel p2 = new JPanel();

	Socket s = null; // 创建客户端套接字
	DataOutputStream dos = null; // 输出流
	DataInputStream dis = null; // 输入流

	boolean bConnected = false; // 连接标志

	Thread t = new Thread(new RecToServer()); // 多线程--new Runnable()接口

	// 窗口布局
	public void launchFrame() {

		taContent.setEditable(false);

		p2.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 5)); // 使用流布局
		p2.add(send); // 3个按钮--send、connect、clear
		p2.add(connect);
		p2.add(clear);

		Container con = this.getContentPane(); // 实例化容器

		con.add(taContent, "North"); // 容器中添加文本域
		con.add(tfTxt, "Center"); // 容器中添加文本框
		con.add(p2, "South"); // 容器中添加面板(面板中是两个按钮)

		this.setSize(300, 350); // this 指代 JFrame
		this.setLocation(400, 200);
		this.setTitle("Chat Client");

		this.setVisible(true);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		// 添加按钮监听
		connect.addActionListener(new Connect()); // 连接按钮
		send.addActionListener(new SendMsg()); // 发送按钮
		clear.addActionListener(new ActionListener() { // 清除按钮监听--使文本框中的内容置空
			public void actionPerformed(ActionEvent e) {
				taContent.setText("");
			}
		});
	}

	// 连接服务器
	public void connectToServer() {
		try {

			s = new Socket("127.0.0.1", 8888); // 客户端创建一个Socket套接字
			dos = new DataOutputStream(s.getOutputStream()); // 数据输出流
			dis = new DataInputStream(s.getInputStream()); // 数据输入流

			bConnected = true; // 连接标识符置为true

		} catch (BindException e) {
			System.out.println("找不到指定的服务器");
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	// 断开链接
	public void disConnect() {
		try {
			if (s != null) {
				s.close(); // Socket s = null
			}

			if (dos != null) {
				dos.close(); // DataOutputStream dos = null
			}
			if (dis != null) {
				dis.close(); // DataInputStream dis = null
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	// 主程序
	public static void main(String args[]) {
		TCPClient tc = new TCPClient(); // 实例化TCPlient对象
		tc.launchFrame(); // 主程序
	}

	// 连接按钮----监听
	private class Connect implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			if (e.getActionCommand() == "连接") { // e.getActionCommand()==获取按钮上的文字(连接)

				connectToServer(); // 连接服务器
				try {
					t.start(); // 启动多线程 Thread t=new Thread(new RecToServer())
				} catch (IllegalThreadStateException ex) {
				}

				connect.setText("断开连接"); // 当连接上服务器以后,连接按钮 变为 断开连接按钮

			} else if (e.getActionCommand() == "断开连接") {
				disConnect(); // 断开连接
				connect.setText("连接");
			}

		}
	}

	// 发送按钮--监听
	private class SendMsg implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			if (connect.getActionCommand() == "连接") { // 还没有连接上
				/*
				 * showMessageDialog(Component parentComponent, Object message, String title,int messageType) 
				 * 第一个参数:parentComponent---设置了可以改变窗体的主题信息
				 * 第二个参数:message---显示的消息内容 第三个参数:title---提示框的标题
				 * 第四个参数:messageType---设置了信息提示内容的图标,默认值为INFORMATION_MESSAGE或1
				 */
				JOptionPane.showMessageDialog(TCPClient.this, // 出现提示框
						"没有找到指定的服务器", "错误提示", 1);
			} else { // 连接上了
				String str = tfTxt.getText(); // 获取文本框(发送框)中的内容
				tfTxt.setText("");   // 将文本框(发送框)中的内容置零

				try {
					dos.writeUTF(str);   // 将文本框(发送框)中的内容输出
					dos.flush();        // 不断刷新
				} catch (SocketException ex) {   // 
					System.out.println("没有找到指定的服务器");
					JOptionPane.showMessageDialog(TCPClient.this, "没有找到指定的服务器", "错误提示", 1);
				} catch (IOException ex) {
					ex.printStackTrace();
				}
			}

		}
	}

	// 多线程接口
	private class RecToServer implements Runnable {
		public void run() {
			try {
				while (bConnected) {   // 连接标志= true 时
					String str = dis.readUTF();    // 读入数据
					// System.out.println(str);

					taContent.append(str + "\n");   // 在文本域中添加聊天内容str
				}
			} catch (SocketException e) {
				System.out.println("服务器已关闭");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值