Python 官方文档:入门教程 => 点击学习
本文实例为大家分享了Java实现多线程聊天室的具体代码,供大家参考,具体内容如下 之前呢已经用单线程的方式来实现了聊天室,但其实它的功能并不齐全,下面用多线程来实现,功能会比单线程聊
本文实例为大家分享了Java实现多线程聊天室的具体代码,供大家参考,具体内容如下
之前呢已经用单线程的方式来实现了聊天室,但其实它的功能并不齐全,下面用多线程来实现,功能会比单线程聊天室更加齐全,也更人性化一点
多线程版本的聊天室
1.维护所有的在线用户
3.群聊功能:客户端发送消息,所有的客户端都能接收到
4.私聊功能:客户端与指定客户端进发送和接收消息
5.退出功能: 从服务器客户端集合中移除客户端
1.注册功能:创建Socket对象,给服务器发送注册执行(消息)
2.群聊功能:客户端发送和接收数据
3.私聊功能:客户端指定客户端(用户),发送和接收数据
4.退出功能:给服务器发送退出指令(消息)
5.命令行的交互式输入输出
首先,要实现服务端与客户端之间的连接
这里是使用套接字建立tcp连接:
(1)服务器端先实例化一个描述服务器端口号的ServerSocket对象
(2)客户端要创建Socket对象来连接指定的服务器端
(3)服务器端调用ServerSocket类的accept()方法来监听连接到服务器端的客户端信息
(4)若服务器端与客户端连接成功,双方将返回一个Socket对象,此时双方可以进行通信
(5)服务器端与客户端使用I/O流进行连接,服务端的输出流连接客户端的输入流,客户端的输出流连接服务端的输入流
(6)使用close()方法关闭套接字(一定要记得关闭)
2.因为是拥有一个服务端来实现多个客户端的连接,此处还要解决的是多线程的问题。
每个客户端需要两个线程,来分别处理向服务端发送消息和向服务端接收消息
而服务端,当每增加一个客户端与服务端连接,服务端都要多创建一个线程来处理与客户端的连接
Server类
package test.Server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class server {
public static void main(String[] args) {
try {
int port = 6666;
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("服务器启动..." + serverSocket.getLocalSocketAddress()); //服务器启动,打印本地地址
//线程池
ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
while (true) { //死循环
Socket client = serverSocket.accept();
System.out.println("有客户端连接到服务器:" + client.getRemoteSocketAddress());
executorService.execute(new HandlerClient(client));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
HandlerClient类
package test.Server;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.ConcurrentHashMap;
public class HandlerClient implements Runnable {
private static final Map<String,Socket> ONLINE_CLIENT_MAP =
new ConcurrentHashMap<String, Socket>(); //静态是为了不让对象变化,final不让对象被修改,ConcurrentHashMap是线程安全的类
//static final修饰后变量名应该用常量--大写字母加下划线分隔
private final Socket client;
public HandlerClient(Socket client) { //HandlerClient在多线程环境下调用,所以会产生资源竞争,用一个并发的HashMap
this.client = client; //为了防止变量被修改,用final修饰
}
//@Override
public void run() {
try {
InputStream clientInput=client.getInputStream(); //获取客户端的数据流
Scanner scanner = new Scanner(clientInput); //字节流转字符流
while(true){
String data = scanner.nextLine(); //读数据,按行读
if(data.startsWith("reGISter:")){
//注册
String userName = data.split(":")[1];//冒号分隔,取第一个
register(userName);
continue;
}
if(data.startsWith("groupChat:")){
String message = data.split(":")[1];
groupChat(message);
continue;
}
if(data.startsWith("privateChat:")){
String [] segments = data.split(":");
String targetUserName = segments[1].split("\\-")[0]; //取目标用户名
String message = segments[1].split("\\-")[1]; //因为要取两次,所以用数组 //取发送的消息内容
privateChat(targetUserName,message);
continue;
}
if(data.equals("bye")){
//表示退出
bye();
continue;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void bye() {
for(Map.Entry<String,Socket> entry : ONLINE_CLIENT_MAP.entrySet()){
Socket target = entry.getValue();
if(target.equals(this.client)){ //在在线用户中找到自己并且移除
ONLINE_CLIENT_MAP.remove(entry.geTKEy());
break;
}
System.out.println(getCurrentUserName()+"退出聊天室");
}
printOnlineClient();//打印当前用户
}
private String getCurrentUserName(){
for (Map.Entry<String, Socket> entry : ONLINE_CLIENT_MAP.entrySet()) {
Socket target = entry.getValue(); //getvalue得到Socket对象
if(target.equals(this.client)){ //排除群聊的时候自己给自己发消息的情况
return entry.getKey();
}
}
return "";
}
private void privateChat(String targetUserName, String message) {
Socket target = ONLINE_CLIENT_MAP.get(targetUserName);//获取目标用户名
if(target == null){
this.sendMessage(this.client,"没有这个人"+targetUserName,false);
}else{
this.sendMessage(target,message,true);
}
}
private void groupChat(String message) {
for (Map.Entry<String, Socket> entery : ONLINE_CLIENT_MAP.entrySet()) {
Socket target = entery.getValue(); //getvalue得到Socket对象
if(target.equals(this.client)){
continue; //排除群聊的时候自己给自己发消息的情况
}
this.sendMessage(target,message,true);
}
}
private void register(String userName) {
if(ONLINE_CLIENT_MAP.containsKey(userName)){
this.sendMessage(this.client,"您已经注册过了,无需重复注册",false);
}else{
ONLINE_CLIENT_MAP.put(userName,this.client);
printOnlineClient();
this.sendMessage(this.client,"恭喜"+userName+"注册成功\n",false);
}
}
private void sendMessage(Socket target,String message,boolean prefix){
OutputStream clientOutput = null; //value是每一个客户端
try {
clientOutput = target.getOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(clientOutput);
if(prefix) {
String currentUserName = this.getCurrentUserName();
writer.write("<" + currentUserName + "说:>" + message + "\n");
}else{
writer.write( message + "\n");
}
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
private void printOnlineClient(){
System.out.println("当前在线人数:"+ONLINE_CLIENT_MAP.size()+","+"用户名如下列表:");
for(String userName : ONLINE_CLIENT_MAP.keySet()){ //Map的key为用户名
System.out.println(userName);
}
}
}
Client类
package Cilent;
import java.io.IOException;
import java.net.Socket;
public class cilent {
public static void main(String[] args) {
try {
//读取地址
String host = "127.0.0.1";
//读取端口号
int port = 6666;
Socket client = new Socket(host,port); //先写数据再读数据,读写线程分离
new ReadDataFromServerThread(client).start();//启动读线程
new WriteDataToServerThread(client).start();//启动写线程
} catch (IOException e) {
e.printStackTrace();
}
}
}
WriteDateToServer类
package Cilent;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;
public class WriteDataToServerThread extends Thread{
private final Socket client;
public WriteDataToServerThread(Socket client){
this.client = client;
}
@Override
public void run(){
try {
OutputStream clientOutput = this.client.getOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(clientOutput);
Scanner scanner = new Scanner(System.in); //有客户端输入数据
while(true){
System.out.print("请输入>>");
String data = scanner.nextLine(); //读数据
writer.write(data+"\n");
writer.flush();
if(data.equals("bye")){
System.out.println("您已下线...");
break;
}
}
this.client.close();
} catch (IOException e) {
// e.printStackTrace();
}
}
}
ReadDateFromServer类
package Cilent;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.Scanner;
public class ReadDataFromServerThread extends Thread {
private final Socket client;
public ReadDataFromServerThread(Socket client){
this.client=client;
}
@Override
public void run(){
try {
InputStream clientInput = this.client.getInputStream();
Scanner scanner = new Scanner(clientInput);
while(true){
String data = scanner.nextLine();//按行读数据
System.out.println("来自服务端消息:"+data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
--结束END--
本文标题: Java实现多线程聊天室
本文链接: https://www.lsjlt.com/news/129179.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-03-01
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0