当前位置: 代码迷 >> 综合 >> TCP聊天室
  详细解决方案

TCP聊天室

热度:71   发布时间:2023-09-20 23:16:40.0

用TCP实现聊天室,可多人共同聊天,也可与别人私聊。

一、建立客户端和服务端

二、创建客户端发送线程和接收线程,实现同时读和写

三、服务端创建死循环,以实现循环接收和发送信息

四、创建客户端与服务端的连接通道,不同客户端对应不同连接通道,并将不同通道放到集合list中

五、在连接通道MyChannel中实现向多人聊天,比如:A客户端发送消息,A通道获取该消息msg,其他通道将此msg发送到各自的客户端

六、在连接通道MyChannel中实现私聊,约定私聊格式为@name:content,遍历集合,使用此用户名的连接通道就会向自己客户端发送msg,实现私聊


服务器端
package com.mipo.tcp.demo4;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 Administrator**/
public class Server {//创建集合private List<MyChannel> all = new ArrayList<MyChannel>();public static void main (String[] args) throws IOException {new Server().start();}public void start() throws IOException {//创建服务器,指定端口ServerSocket server = new ServerSocket(7777);while (true) {//接收客户端连接,阻塞式(若客户端连接成功,则执行下面的程序,否则不执行)Socket client = server.accept();//创建一条通道MyChannel channel = new MyChannel(client);//将不同通道添加到集合中,方便统一管理all.add(channel);//一条通道是一个独立的线程new Thread(channel).start();}}//内部类//MyChannel代表的是客户端与服务器之间的连接通道,不同的客户端有不同的连接通道private class MyChannel implements Runnable{//输入流private DataInputStream dis;//输出流private DataOutputStream dos;//判断程序是否正常运行private boolean isRunning = true;//聊天室用户名private String name;//构造器public MyChannel(Socket client) {try {dis = new DataInputStream(client.getInputStream());dos = new DataOutputStream(client.getOutputStream());//当前对象的名称=控制台输入的用户名this.name = dis.readUTF();//向自己发送消息this.send("歡迎您進入聊天室");//发送系统信息sendOthers(this.name+"進入了聊天室", true);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();//出现异常,关闭输入输出流CloseUtil.closeAll(dis,dos);//设置程序运行状态isRunning = false;}}//读取数据private String receive() {String msg = "";try {msg = dis.readUTF();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();CloseUtil.closeAll(dis);isRunning = false;//移除自身all.remove(this);}return msg;}//发送数据private void send(String msg) {if(null == msg || msg.equals("")) {return;}try {//发送信息dos.writeUTF(msg);//刷新dos.flush();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();CloseUtil.closeAll(dos);isRunning = false;all.remove(this);}}//发送给其他客户端private void sendOthers(String msg,boolean sys) {//是否为私聊,约定格式为:      @姓名:if(msg.startsWith("@") && msg.indexOf(":")>-1) {//获取子串,左包由不包String name = msg.substring(1, msg.indexOf(":"));//获取contentString content = msg.substring(msg.indexOf(":")-1);//foreach(元素类型 变量:数组或集合表达式)for(MyChannel other:all) {if(other.name.equals(name)) {other.send(this.name+"对您悄悄说:"+content);}}}else{//遍历容器for(MyChannel other:all) {if(other==this) {continue;//跳过本次循环,执行下一次循环}if(sys){//系统消息other.send("系统消息:"+msg);}else{//发送其他客户端other.send(this.name+"对所有人说:"+msg);}}}	}@Overridepublic void run() {// TODO Auto-generated method stubwhile(isRunning) {sendOthers(receive(),false);}}}
}


客户端
package com.mipo.tcp.demo4;import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
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 IOException, IOException {System.out.println("请输入您的名称");//获取控制台输入流BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//读取控制台输入的文本String name = br.readLine();if(name.equals("")) {return;//如果输入的姓名为"",程序执行到此终止}//建立客户端,必须指定服务器+服务器端口,此时就在连接Socket client = new Socket("localhost",7777);//发送线程Thread t1 = new Thread(new Send(client, name));t1.start();//接收线程Thread t2 = new Thread(new Receive(client));t2.start();}}


发送线程
package com.mipo.tcp.demo4;import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;/*** 客户端发送数据线程* @author Administrator**/
public class Send implements Runnable{//控制台输入流private BufferedReader console;//管道输出流private DataOutputStream dos;//控制线程private boolean isRunning = true;//聊天室用户名private String name;//构造器public Send() {console = new BufferedReader(new InputStreamReader(System.in));}public Send(Socket client,String name) {this();//指无参构造器创建的对象try {dos = new DataOutputStream(client.getOutputStream());//当前调用send的方法的客户端的用户名this.name = name;//将用户名发送到服务器send(name);} catch (IOException e) {//e.printStackTrace();//关闭输出流CloseUtil.closeAll(dos,console);//当遇到问题,线程不再运行isRunning = false;}}//从控制台接收数据private String getMsgFromConsole () {try {return console.readLine();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return "";}//1、从控制台接收数据//2、再发送数据public void send(String msg) {if (null != msg && !msg.equals("")) {try {dos.writeUTF(msg);dos.flush();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();CloseUtil.closeAll(dos,console);isRunning = false;}}}@Overridepublic void run() {// TODO Auto-generated method stub//循环发送,当程序出现异常,isRunning=falsewhile (isRunning) {send(getMsgFromConsole());}}}


接收线程
package com.mipo.tcp.demo4;import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;/*** 客户端接收线程* @author Administrator**/
public class Receive implements Runnable {//输入流private DataInputStream dis;//线程标识private boolean isRunning = true;//构造器public Receive() {}public Receive(Socket client) {try {dis = new DataInputStream(client.getInputStream());} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();isRunning = false;CloseUtil.closeAll(dis);}}//接收数据public String receive() {String msg = "";try {//该方法读取使用 UTF-8 修改版格式编码的 Unicode 字符串的表示形式;然后以 String 的形式返回此字符串。msg = dis.readUTF(); } catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();isRunning = false;CloseUtil.closeAll(dis);} return msg;}@Overridepublic void run() {// TODO Auto-generated method stubwhile (isRunning) {System.out.println(receive());}}}


关闭流工具类
package com.mipo.tcp.demo4;import java.io.Closeable;
import java.io.IOException;/*** 关闭流的方法* @author Administrator**/
public class CloseUtil {public static void closeAll(Closeable...io) {for (Closeable temp:io) {//foreachif (null != temp) {try {temp.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}
}




  相关解决方案