TCP之实现简单聊天室

来源:互联网 发布:php魔术方法isset() 编辑:程序博客网 时间:2024/06/04 22:46
已测试:
1.先启动Server, 后启动Client
2.实现多Client同时登陆

3.实现群聊和私聊(格式: @name:内容)

--------------------------------------------------------------------------------------------------------------------------------------------------------

import java.io.BufferedReader;import java.io.Closeable;import java.io.DataOutputStream;import java.io.IOException;/** * 关闭所有流工具类 * @author Ray * */public class CloseUtil {public static void closeAll(Closeable...io) {for(Closeable temp : io) {if(temp != null) {try {temp.close();} catch (IOException e) {e.printStackTrace();}}}}}

import java.io.DataInputStream;import java.io.IOException;import java.net.Socket;/** * 接收数据    * 多线程实现 * @author Ray * */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) {//如果错误isRunning = false;CloseUtil.closeAll(dis);}}//接收数据public String receive() {String msg = "";try {msg = dis.readUTF();} catch (IOException e) {//如果错误isRunning = false;CloseUtil.closeAll(dis);}return msg;}@Overridepublic void run() {//线程体while(isRunning) {System.out.println(receive());}}}
package cn.Ray.net.tcp.chat.demo05;import java.io.BufferedReader;import java.io.DataOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.net.Socket;/** * 发送数据   * 多线程实现  * @author Ray * */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()); //返回此套接字的输出流。this.name = name;send(this.name);} catch (IOException e) {//如果错误isRunning = false;CloseUtil.closeAll(dos,console);}}//1.从控制台接收数据private String getMsgFromConsole() {try {return console.readLine();} catch (IOException e) {e.printStackTrace();}return "";}//2.发送数据public void send(String msg) {try {if(msg != null && !msg.equals("")) {dos.writeUTF(msg);dos.flush(); //强制刷新}} catch (IOException e) {//如果错误isRunning = false;CloseUtil.closeAll(dos);}}@Overridepublic void run() {//线程体while(isRunning) {send(getMsgFromConsole());}}}

import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.Socket;import java.net.UnknownHostException;/** * 创建客户端:发送+接收数据 * 写出数据:输出流 * 读取数据:输入流 *  * 输入流与输出流在同一个线程内应该独立处理,彼此独立 *  * 加入名称 * @author Ray * */public class Client {public static void main(String[] args) throws UnknownHostException, IOException {System.out.println("请输入用户名: ");//从控制台获取nameBufferedReader br = new BufferedReader(new InputStreamReader(System.in));String name = br.readLine();if(name.equals("")) {return;}//创建客户端Socket client = new Socket("localhost",9999);//控制台输入出流new Thread(new Send(client,name)).start(); //一条路径(发送数据)new Thread(new Receive(client)).start(); //一条路径(接收数据)}}
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;/** * 创建服务器 * 写出数据:输出流 * 读取数据:输入流 * 使用容器: * 1.加入容器管理道路  private List<MyChannel> all = new ArrayList<>(); * 2.每当来一条道路就加入到容器中  all.add(channel); *  3.出现异常,挪出容器  all.remove(this); *  3.发送信息给其他人相当于遍历容器 * @author Ray * */public class Server {private List<MyChannel> all = new ArrayList<>();public static void main(String[] args) throws IOException {new Server().start();}public void start() throws IOException {ServerSocket server = new ServerSocket(9999);while(true) {Socket client = server.accept();MyChannel channel = new MyChannel(client);all.add(channel); //把管道加入到容器中,统一管理new Thread(channel).start(); //一条道路}}/** * 私有内部类, 方便访问外部类属性方法 * 一个客户端一条道路 * 1.输入流 * 2.输出流 * 3.接收数据 * 4.发送数据 * @author Ray * */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); //如果为true表示系统信息,false表示用户信息} catch (IOException e) {isRunning = false;CloseUtil.closeAll(dis,dos);all.remove(this); //移除自身}}/** * 读取数据 * @return */private String receive() {String msg = "";try {msg = dis.readUTF();} catch (IOException e) {isRunning = false;CloseUtil.closeAll(dis);all.remove(this); //移除自身}return msg;}/** * 发送数据 * @param msg */private void send(String msg) {if(msg == null || msg.equals("")) {return;}try {dos.writeUTF(msg);dos.flush();} catch (IOException e) {isRunning = false;CloseUtil.closeAll(dos);all.remove(this);//移除自身}}/** * 发送给其他人 * 遍历容器 */private void sendOthers(String msg,boolean sys) {//是否为私聊  约定的if(msg.startsWith("@") && msg.indexOf(":") > -1) { //私聊//获取nameString name = msg.substring(1,msg.indexOf(":"));String content = msg.substring(msg.indexOf(":") + 1); //左闭右开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() {while(isRunning) {sendOthers(receive(),false);}}}}




原创粉丝点击