当前位置:   article > 正文

Java网络编程:TCP实现群聊&私聊代码_使用tcp实现多人聊天窗口,可实现群聊与私聊代码

使用tcp实现多人聊天窗口,可实现群聊与私聊代码

Java网络编程:TCP实现群聊&私聊代码

和上一篇博客差不多,只不过是在群里的基础之上增加了私聊的功能,我们约定,私聊格式为:@xxx:msg

如何实现私聊呢,加入客户端c给服务器发送消息,服务器不再是把消息转发给所以除c以外的客户端,而是解析数据格式,转发给与name(“:”之前,“@”之后的字符串)有相同名字的客户端即可。

群聊功能与之前类似,这里不再说说明。

下面是所有类的代码:

(1)Server类的代码:

package chat4;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;

/**注意:实现私聊(约定数据格式为:@xxx:msg
 * 在线聊天室:使用容器实现群聊
 * 服务器
 * @author Administrator
 * 需要修改和遍历数据的时候使用list会操作不方便
 * 问题:为什么加了static,在主函数里面就没错啦?
 * 
 */
public class Server {
	//CopyOnWriteArrayList和list用法一样
	private static CopyOnWriteArrayList<Channel> all=new CopyOnWriteArrayList<Channel>();
	public static void main(String[] args) throws IOException {
		System.out.println("----------server----------");
		
		//创建服务器
		ServerSocket server=new ServerSocket(8977);
		
		while(true) {
			//阻塞式等待客户端的连接
			Socket client=server.accept();
			System.out.println("一个客户端连接上。。。");
			Channel c=new Channel(client);
			all.add(c);//容器管理所有的成员
			new Thread(c).start();
		}
	}
	
	//一个客户代表一个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());
				dos=new DataOutputStream(client.getOutputStream());
				isRunning=true;
				
				//获取名称
				name=receiveMsg();
				this.sendMsg(name+"同学,"+"欢迎您的到来");
				sendOther(this.name+"加入群聊天室",true);
				
			} catch (IOException e) {
				System.out.println("-----1   出问题----");//自己方便观察哪里出问题
				release();//注意:这里做了修改
			}
		}
		
		//接收消息(服务器读取客户端发过来的信息)
		private String receiveMsg() {
			String msg="";
			try {
				msg=dis.readUTF();
			} catch (IOException e) {
				System.out.println("-----receive 出问题----");//自己方便观察哪里出问题
				release();//注意:这里做了修改
			}
			return msg;
		}
		
		//发送消息(服务器反馈信息给客户端)
		private void sendMsg(String msg) {
			try {
				dos.writeUTF(msg);
				dos.flush();
			} catch (IOException e) {
				System.out.println("-----send 出问题----");//自己方便观察哪里出问题
				release();//注意:这里做了修改
			}
		}
		
		//发送消息(服务器反馈信息(其实就是服务器读取的当前客户端的消息)给其他所有的客户端(除了当前客户端)
		private void sendOther(String msg,boolean isSysMsg) {
			boolean isPrivate=msg.startsWith("@");
			if(isPrivate) {//是私聊消息
				int idx=msg.indexOf(":");
				//获取目标和数据
				String targetName=msg.substring(1,idx);
				msg=msg.substring(idx+1);
				System.out.println("服务器收到的私聊信息为:"+targetName+"&"+msg);
				for(Channel other:all) {
					if(other.name.equals(targetName)) {//找到目标
						other.sendMsg(this.name+":"+msg);
					}
				}
			}else {
				for(Channel other:all) {//服务器把收到的客户端的消息发给其余所有的客户端(除了当前客户端)
					if(other!=this) {
						if(isSysMsg) {
							other.sendMsg(msg);//系统消息
						}else {
							other.sendMsg(this.name+":"+msg);//群聊消息
						}
					}
				}
			}
			
		}
		
		//释放资源
		private void release() {
			this.isRunning=false;//释放资源意味着该该客户端要停下来
			Utils.close(dis,dos,client);//自己写的一个工具类Utils
			all.remove(this);//当前客户端退出
			sendOther(this.name+"离开了聊天室。。。", true);
		}

		@Override
		public void run() {
			while(isRunning) {
				//流程:服务器读取客户端消息-服务器发送反馈消息给客户端-释放资源
				String msg=receiveMsg();
				//System.out.println("服务器读取到的信息为:"+msg);
				if(!msg.equals("")) {
					//sendMsg(msg);
					sendOther(msg,false);//群聊消息
				}
				
			}
			//release();//老师这里没有释放
		}
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137

(2)Client类的代码(下面的Receive类和Send类为Client类所用):

package chat4;

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

/**注意:
 * 在线聊天室:使用容器实现群聊
 * 客户端
 * @author Administrator
 *
 */
public class Client {
	public static void main(String[] args) throws UnknownHostException, IOException {
		System.out.println("---------------client--------------");
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		System.out.println("请输入用户名:");
		String name=br.readLine();
		//建立套接字
		Socket client=new Socket("localhost", 8977);
		
		//客户端发送消息(先读取控制台的内容,再写入到客户端的输出流里)
		new Thread(new Send(client,name)).start();
		new Thread(new Receive(client)).start();
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

(3)Receive类的代码:

package chat4;

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

/**
 *作用: 被MutiClient类用到,是客户端用来接收服务器反馈的消息的
 *客户端读取服务器反馈的消息,并显示输出
 * @author Administrator
 *
 */
public class Receive implements Runnable {
	private DataInputStream dis;
	private Socket client;
	private boolean isRunning;
	public Receive(Socket client) {
		this.client=client;
		isRunning=true;
		try {
			dis=new DataInputStream(client.getInputStream());
		} catch (IOException e) {
			System.out.println("客户端的Receive构造器有问题");
			release();
		}
	}
	
	@Override
	public void run() {
		while(isRunning) {
			String msg=receiveMsg();
			if(!msg.equals("")) {
				System.out.println(msg);
			}
		}
	}
	
	private String receiveMsg() {
		String msg="";
		try {
			msg=dis.readUTF();
		} catch (IOException e) {
			System.out.println("客户端的receiveMsg有问题");
			release();
		}
		return msg;
	}
	//释放资源
	private void release() {//内部类的使用
		this.isRunning=false;//释放资源意味着该该客户端要停下来
		Utils.close(dis,client);//自己写的一个工具类Utils
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

(4)Send类的代码:

package chat4;

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

/**
 * 作用:被MutiClient类用到,是客户端用来发送消息的
 * 具体操作是:客户端读取控制台消息--写入到client的输出流
 * @author Administrator
 *
 */
public class Send implements Runnable {
	private BufferedReader console;
	private DataOutputStream dos;
	private Socket client;
	private boolean isRunning;
	private String name;
	public Send(Socket client,String name) {
		this.client=client;
		this.name=name;
		console=new BufferedReader(new InputStreamReader(System.in));
		try {
			dos=new DataOutputStream(client.getOutputStream());
			
			sendMsg(name);//发送名字
			isRunning=true;
		} catch (IOException e) {
			System.out.println("客户端的send构造器有问题");
			this.release();
		}
	}
	
	@Override
	public void run() {
		while(isRunning) {
			//客户端读取控制台消息--写入到client的输出流
			String msg=ConsoleMsg();
			if(!msg.equals("")) {
				sendMsg(msg);
			}
			
		}
	}
	private String ConsoleMsg() {//先读取控制台的内容
		String msg="";
		try {
			msg=console.readLine();
		} catch (IOException e) {
			System.out.println("客户端的ConsoleMsg有问题");
			this.release();
		}
		return msg;
		
	}
	private void sendMsg(String msg) {//再写入到客户端的输出流里
		try {
			dos.writeUTF(msg);
			dos.flush();//这个一定不能忘记啦
		} catch (IOException e) {
			System.out.println("客户端的sendMsg有问题");
			this.release();
		}
	}
	//释放资源
	private void release() {//内部类的使用
		this.isRunning=false;//释放资源意味着该该客户端要停下来
		Utils.close(dos,client);//自己写的一个工具类Utils
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

(5)Utils类的代码(编写工具类,方便资源的释放):

package chat4;

import java.io.Closeable;

/**
 * 自己写一个释放资源的工具类
 * @author Administrator
 *
 */
public class Utils {
	public static void close(Closeable... targets) {
		for(Closeable target:targets) {
			try {
				if(null!=target) {
					target.close();
				}
			}catch(Exception e){
				
			}
		}
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

运行结果如下:

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/178589
推荐阅读
相关标签
  

闽ICP备14008679号