Java项目——模拟QQ群聊和私聊!!!(网络编程+多线程)

前几天学习了多线程,最近在学习网络编程,了解了UDP之后又学习了TCP,听一下大佬说,要看看你这两个东西掌握的怎么样,最好的办法就是写一个模拟QQ群聊和私聊,经过这几天的学习,以及不断的完善,终于可以实现了!!!

这是源码:

链接:https://pan.baidu.com/s/1dCwV_CI7maTwktePtaCtQw
提取码:qwka

目录

一、聊天演示

二、服务器端

三、客户端

四、Util工具类


一、聊天演示

这个是我自己模拟的截图,由于只有一台电脑,故只能运行多个窗口进行演示,这里的服务器端是Server,客户端有三个分别是111、222和333,当我们正常聊天时是群聊状态,想要进行私聊可以进行@XXX:即可,该系统可以完成多台电脑的联机,已实验

Java项目——模拟QQ群聊和私聊!!!(网络编程+多线程)_第1张图片

二、服务器端

下面给大家详细的讲解一下关于QQ群聊和私聊的具体思想,首先这个程序用了TCP协议,也叫做三次握手协议,为什么这样讲呢,是因为在这个TCP协议中分客户端和服务器端,客户端要想向服务器端发送消息,首先要先给服务器打个招呼,看看服务器是否能正常工作,如果可以,服务器会给一个回复,当客户端接到这个肯定的回复后才能向服务器发送消息,所以需要先启动服务器端,其中,服务器端和客户端之间的信息传输都是以流的方式进行的,如何启动服务器端呢,这个是我写的代码,里面都有注释:

package com.TCP;

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

/**
 * 该类实现的是服务器端,也只有启动了服务器,客户端才能进行信息的交流
 * @author 11852
 *
 */

public class Server {
	
	//这个list集合是用来存储各个客户端的,每当有一个客户端建立了连接,这里就会存储起来
	private static List list = new ArrayList();

	public static void main(String[] args) throws IOException {
		System.out.println("---Server---");
		// 指定端口,使用ServerSocket创建服务器,此时创建了一个名字为server端口号为12345的服务器
		ServerSocket server = new ServerSocket(12345);

		boolean flag = true;
		while (flag) {
			// 阻塞式等待连接accept,服务器调用accept方法,即是获得一个客户端的连接
			//如果没有客户端连接,则该程序处于堵塞状态
			Socket client = server.accept();
			System.out.println("一个客户端建立了连接");
			
			//客户端与服务器建立了连接之后,获取该客户端的输入流和输出流对象
			Channel channel = new Channel(client);
			list.add(channel);// 用list容器管理所有的人员
			//这里是实现多线程,即每个客户端都可以进行与服务器端的交流
			new Thread(channel).start();
		}
		server.close();
	}

	// 一个客户端代表一个Channel
	static class Channel implements Runnable {
		private DataInputStream dis;
		private DataOutputStream dos;
		private Socket client;
		private boolean isRunning;
		private String name;

		//这是构造方法
		public Channel(Socket client) {
			this.client = client;
			try {
				dis = new DataInputStream(client.getInputStream());
				isRunning = true;
				name = receive();
			} catch (IOException e) {
				relese();
			}
			try {
				dos = new DataOutputStream(client.getOutputStream());
			} catch (IOException e) {
				relese();
			}
		}

		// 接收消息
		private String receive() {
			String msg = "";
			try {
				msg = dis.readUTF();
			} catch (IOException e) {
				relese();
			}
			return msg;
		}

		// 发送消息
		private void send(String msg) {
			try {
				dos.writeUTF(msg);
			} catch (IOException e) {
				relese();
			}
		}

		// 群聊,发给别人
		private void sendOthers(String msg) {

			// 私聊格式@XXX:这里是找到以@开头的信息
			if (msg.startsWith("@")) {
				int idx = msg.indexOf(":");
				String targetName = msg.substring(1, idx);
				msg = msg.substring(idx + 1);
				for (Channel other : list) {
					if (other.name.equals(targetName)) {
						other.send(this.name + ":" + msg);
					}
				}
			} else {
				for (Channel other : list) {
					if (other == this) {
						continue;
					} else {
						other.send(this.name + ":" + msg);
					}

				}
			}
		}

		// 释放资源
		private void relese() {
			this.isRunning = false;
			//这里的Util是自定义的一个类
			Util.close(dis, dos, client);
		}

		@Override
		public void run() {
			while (isRunning) {
				String msg = receive();
				if (!msg.equals("")) {
					sendOthers(msg);
				}
			}
		}
	}
}

三、客户端

客户端中用到了接收信息、发送信息以及释放资源

package com.TCP;

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

public class Client {
	public static void main(String[] args) throws IOException {
		System.out.println("---Client---");

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		System.out.println("请输入用户名");
		String name = br.readLine();
		// 建立连接,使用Socket创建连接,括号内是服务器的地址和端口
		Socket client = new Socket("localhost", 12345);

		// 客户端发送消息
		new Thread(new Send(client, name)).start();
		new Thread(new Receive(client)).start();
	}
}

在实现客户端的时候,我这里是在控制台输入的信息,也可以进行跨级聊天,但前提是要在同一个局域网内,对于客户端来说,需要客服端进行发送信息和接收信息,首先看看接收信息吧

package com.TCP;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;

public class Receive implements Runnable {
	private DataInputStream dis;
	private Socket client;
	private boolean isRunning;

	//这里是传过来了一个客户端对象,并获得了输入流对象
	public Receive(Socket client) {
		this.client = client;
		try {
			dis = new DataInputStream(client.getInputStream());
			isRunning = true;
		} catch (IOException e) {
			release();
		}
	}

	//这里是实现了获取信息
	private String receive() {
		String msg = "";
		try {
			msg = dis.readUTF();
		} catch (IOException e) {
			release();
		}
		return msg;
	}
	
	//这是重写了run方法,实现多线程,也就是多个客户端都能与服务器打交道
	@Override
	public void run() {
		while (isRunning) {
			String msg = receive();
			if (!msg.equals("")) {
				System.out.println(msg);
			}
		}
	}

	// 释放资源
	private void release() {
		this.isRunning = false;
		Util.close(dis, client);
	}
}

然后就是发送类了,发送跟接收差不多,基本思路是一样的

package com.TCP;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

public class Send implements Runnable {
	private BufferedReader console;
	private DataOutputStream dos;
	private Socket client;
	private boolean isRunning;

	// 这里用到了名字,就是知道是谁谁发的信息
	public Send(Socket client, String name) {
		console = new BufferedReader(new InputStreamReader(System.in));
		this.client = client;
		try {
			dos = new DataOutputStream(client.getOutputStream());
			this.isRunning = true;
			send(name);

		} catch (IOException e) {
			release();
		}
	}

	// 这里是重写了run方法
	@Override
	public void run() {
		while (isRunning) {
			String msg = getStrFromConsole();
			if (!msg.equals("")) {
				send(msg);
			}

		}

	}

	// 这里是发送消息
	private void send(String msg) {
		try {
			dos.writeUTF(msg);
			dos.flush();
		} catch (IOException e) {
			release();
		}
	}

	// 这里是获取控制台输入的信息
	private String getStrFromConsole() {
		String msg = "";
		try {
			msg = console.readLine();
		} catch (IOException e) {
			release();
		}
		return msg;
	}

	// 释放资源
	private void release() {
		this.isRunning = false;
		Util.close(dos, client);
	}
}

四、Util工具类

这个就是Util类了,这个类就是实现了释放资源

package com.TCP;

import java.io.Closeable;

/**
 * 工具类
 * 
 * @author 11852
 *
 */
public class Util {

	// 释放资源
	public static void close(Closeable... targets) {
		for (Closeable target : targets) {
			try {
				if (target != null) {
					target.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

 

你可能感兴趣的:(java,小系统)