客户端服务器的小型聊天系统

包含到的知识点:

  • 套接字的应用
  • 多线程的认识
  • try-catch的练习
  • 搞清楚创建类的时候,是内部类,外部类,还是匿名类
  • 初步了解调试程序的步骤。

依次增加的功能:

  1. Chat 0.1版本 产生一个窗口
  2. Chat 0.2版本 窗口初步布局
  3. Chat 0.3版本 加入窗口关闭事件
  4. Chat 0.4版本 加入TextField事件处理
  5. Chat 0.5版本 加入ChatServer
  6. Chat 0.6版本 Client连上服务器
  7. Chat 0.7版本 客户端给服务器端发送消息
  8. Chat 0.8版本 修正上个版本的问题,客户端可以发多个语句
  9. Chat 0.9版本 修正上个版本bug
  10. Chat 1.0版本 连上多个客户端
  11. Chat 1.1版本 服务器端转发
  12. Chat 1.2版本 客户端接收
  13. Chat 1.3版本 最后的修正

聊天系统心得

  • 要清楚程序版本迭代的重要性,没有任何程序是一次就能写完美的,在每一次迭代中添加一个新功能。
  • 随时保存代码,Ctrl+S
  • 遇到异常不要直接抛出,不怕困难,考虑周全,有异常了用try-catch语句解决异常,每一次抛出的异常都可能为以后埋雷。
  • 类该怎么写?是写内部类还是外部类,还是匿名类?具体看这个类要做什么
  • 正确的代码100行,完美的代码300行。`

服务器端代码:

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.*;
import java.util.*;

public class ChatServer {
	boolean started = false;// 成员变量
	ServerSocket ss = null;

	List<Client> clients = new ArrayList<Client>();

	public static void main(String[] args) {
		new ChatServer().start();
	}

	public void start() {
		try {
			ss = new ServerSocket(8888);
			started = true;
		} catch (BindException e) {
			System.out.println("端口使用中....");
			System.out.println("请关掉相关程序,请重新运行服务器!");
			System.exit(0);
		} catch (IOException e) {
			e.printStackTrace();
		}

		try {
			while (started) {// 无限接受客户端连接进来
				boolean bConnected = false;
				Socket s = ss.accept();
				Client c = new Client(s);
				System.out.println("a client connected!");
				new Thread(c).start();
				clients.add(c);
//				dis.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				ss.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

	class Client implements Runnable {
		private Socket s;
		private DataInputStream dis = null;
		private DataOutputStream dos = null;
		private boolean bConnected = false;

		public Client(Socket s) {// 构造方法
			this.s = s;
			try {
				dis = new DataInputStream(s.getInputStream());
				dos = new DataOutputStream(s.getOutputStream());
				bConnected = true;
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		public void send(String str) {// 发送方法
			try {
				dos.writeUTF(str);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		public void run() {
			try {
				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);
					}
				}
			} catch (EOFException e) {
				System.out.println("client closed!!");
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					if (dis != null)
						dis.close();
					if (dos != null)
						dos.close();
					if (s != null) {
						s.close();
						s = null;
					}
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		}
	}

}

客户端代码:


```java
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.*;
import java.io.*;

public class ChatClient extends Frame {
	Socket s = null;
	DataOutputStream dos = null;
	DataInputStream dis = null;
	private boolean bConnected = false;

	TextField tfTxt = new TextField();// 输入框
	TextArea taContent = new TextArea();// 显示框

	Thread tRecv = new Thread(new RecvThread());

	public static void main(String[] args) {
		new ChatClient().launchFrame();
	}

	public void launchFrame() {
		setLocation(400, 300);// 设置窗口的位置
		this.setSize(300, 300);// 设置窗口的大小
		add(tfTxt, BorderLayout.SOUTH);// 把输入框放到南边
		add(taContent, BorderLayout.NORTH);// 显示框放到北边
		pack();
		this.addWindowListener(new WindowAdapter() {// 窗口关闭监听按钮

			@Override
			public void windowClosing(WindowEvent e) {
				disconnect();// 关闭窗口的同时,关闭流,关闭套接字
				System.exit(0);// 退出系统
			}

		});
		tfTxt.addActionListener(new TFListener());
		setVisible(true);// 设置为可视化
		connect();// 窗口一打开就直接连接

		tRecv.start();
	}

	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("connected!");
			bConnected = true;
		} catch (UnknownHostException e) {// 连不上主机
			e.printStackTrace();
		} catch (IOException e) {// 输入输出有错误
			e.printStackTrace();
		}
	}

	public void disconnect() {// 断开连接
		try {
			dos.close();
			dis.close();
			s.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		/*
		try {
			bConnected = false;
			tRecv.join();

		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			try {
				dos.close();
				dis.close();
				s.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}*/
	}

	private class TFListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			String str = tfTxt.getText().trim();
//			taContent.setText(str);
			tfTxt.setText("");

			try {
				dos.writeUTF(str);// 写入字符串
				dos.flush();// 刷新流
				// dos.close();//关闭流
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}

	}

	public class RecvThread implements Runnable {
		public void run() {
			try {
				while (bConnected) {
					String str = dis.readUTF();
					taContent.setText(taContent.getText() + str + '\n');
				}
			}catch(SocketException e){
				System.out.println("退出了,再见!");
			} 
			catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}



发布了23 篇原创文章 · 获赞 37 · 访问量 8238

猜你喜欢

转载自blog.csdn.net/weixin_44861399/article/details/104225235
今日推荐