qq怎样创建多人聊天不是群聊介绍;理解2021手机qq创建讨论组

学习编程最重要的就是兴趣引导,所以在学习之前能够看到一个项目成型是非常有必要的。

QQ微信作为大家经常使用的社交软件,一定特别贴切实际。

今天就带大家去了解一下,一个简单的QQ聊天工具其实并不复杂。

首先把这个聊天的项目简单的分为四步,也就是整体的框架(目录)。

Java项目——简单的QQ聊天工具(目录)

一、聊天演示二、服务器端三、客户端四、Util工具类

聊天演示

这个是我自己模拟的截图,由于只有一台电脑,所以只能运行多个窗口进行演示(你也可以多台电脑演示)。qq怎样创建多人聊天不是群聊介绍;理解2021手机qq创建讨论组

演示截图

这里的服务器端是Server,客户端有三个分别是111、222和333,当我们正常聊天时是群聊状态,想要进行私聊可以进行@XXX:即可,该系统可以完成多台电脑的联机。

服务器端

下面给大家详细的讲解一下关于QQ群聊和私聊的具体思想:

首先这个程序用了TCP协议,也叫做三次握手协议。为什么这样讲呢?

因为在这个TCP协议中分客户端和服务器端,客户端要想向服务器端发送消息,要先给服务器打个招呼,判断服务器是否能正常工作。

如果可以,服务器会给一个回复,当客户端接到这个肯定的回复后才能向服务器发送消息,所以需要先启动服务器端,其中,服务器端和客户端之间的信息传输都是以流的方式进行的,如何启动服务器端呢?

这个是我写的代码,里面都有注释:由于从JDK中复制过来的代码格式会被平台调整,所以这里照齐上可能不太好看。

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<Channel> list = new ArrayList<Channel>();

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);

}

}

}

}

}

(由于从JDK中复制过来的代码格式会被平台调整,所以这里照齐上可能不太好看。)

客户端

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

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();

}

}

(由于从JDK中复制过来的代码格式会被平台调整,所以这里照齐上可能不太好看。)

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

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);

}

}

(由于从JDK中复制过来的代码格式会被平台调整,所以这里照齐上可能不太好看。)

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

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);

}

}

由于从JDK中复制过来的代码格式会被平台调整,所以这里照齐上可能不太好看。

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();

}

}

}

}