qq如何创建多人聊天不是群聊(2021手机qq创建讨论组)
学习编程最重要的就是兴趣引导,所以在学习之前能够看到一个项目成型是非常有必要的。
qq微信作为大家经常使用的社交软件,一定特别贴切实际。
今天就带大家去了解一下,一个简单的qq聊天工具其实并不复杂。
首先把这个聊天的项目简单的分为四步,也就是整体的框架(目录)。
java项目——简单的qq聊天工具(目录)
- 一、聊天演示
- 二、服务器端
- 三、客户端
- 四、util工具类
聊天演示
这个是我自己模拟的截图,由于只有一台电脑,所以只能运行多个窗口进行演示(你也可以多台电脑演示)。
演示截图
这里的服务器端是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();
}
}
}
}
下一篇: Oracle PL/SQL语言入门基础