Java网络编程:TCP实现群聊功能代码
实现的功能:群聊
具体操作流程的大致思路:
某个客户端发送消息,服务器将该消息转发给其余客户端(除了自己)。
代码一共分两个端(服务器和客户端(其中客户端一共3个代码)),所以一共5个代码(下面有显示代码)。
【1】客户端代码:(三个代码,其中Send和Receive可以看做被被Client使用创建的,分开封装而已)
【2】服务器代码:(一个代码)
【3】一个工具类Utils代码:
(1)Send类的代码:
package chat3;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();}}@Overridepublic 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}
}
(2)Receive类的代码:
package chat2;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();}}@Overridepublic 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}
}
(3)Client类的代码:
package chat3;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", 8983);//客户端发送消息(先读取控制台的内容,再写入到客户端的输出流里)new Thread(new Send(client,name)).start();new Thread(new Receive(client)).start();}
}
(4)Server类的代码:
package chat3;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;/**注意:* 在线聊天室:使用容器实现群聊* 服务器* @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(8983);while(true) {//阻塞式等待客户端的连接Socket client=server.accept();System.out.println("一个客户端连接上。。。");Channel c=new Channel(client);all.add(c);//容器管理所有的成员new Thread(c).start();}}//一个客户代表一个Channelstatic 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) {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);//自己写的一个工具类Utilsall.remove(this);//当前客户端退出sendOther(this.name+"离开了聊天室。。。", true);}@Overridepublic void run() {while(isRunning) {//流程:服务器读取客户端消息-服务器发送反馈消息给客户端-释放资源String msg=receiveMsg();//System.out.println("服务器读取到的信息为:"+msg);if(!msg.equals("")) {//sendMsg(msg);sendOther(msg,false);//群聊消息}}//release();//老师这里没有释放}}
}
(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){}}}
}
多嘴一句,如果不会运行该代码,自行百度一下,就知道啦!!!很关键。
运行效果如下:
以上就是Java TCP网络编程对于群聊模式功能的简单实现,大家有什么不清楚的,欢迎留言哈(虽然我也很菜的)!!!加油!!!