TCP通信:群聊案例

 

 

复制代码
package Karl.Demo.Test;

import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws Exception {
        //1.创建Sockrt对象,并同时请求与服务端程序连接
        Socket socket=new Socket("127.0.0.1",123456);
        //创造一个独立线程ClentReaerThread用来接受服务端随时都有可能发送来的数据
        //把socket客户端载入到新线程中,表示新线程是用客户端来接受数据,运行新线程
        new ClentReaerThread(socket).start();
        //得到字节输出流,用来发送给服务端
        OutputStream os=socket.getOutputStream();
        //把低级字节输出流包装成数据输出流
        DataOutputStream dos=new DataOutputStream(os);
        Scanner sc=new Scanner(System.in);
        System.out.println("----------客户端开启---------");
        while (true) {
            System.out.println("请输入:");
            String msg = sc.nextLine();

            //用户输入exit,就退出客户端
            if ("exit".equals(msg)) {
                System.out.println("-------退出-------");
                dos.close();
                socket.close();
                break;
            }


            //开始写数据出去
            dos.writeUTF(msg);
            dos.flush();
        }

    }
}
复制代码
复制代码
package Karl.Demo.Test;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class Server {
    //创造集合用来收取客户端上线对象
    public static List<Socket> onListSocket=new ArrayList<>();

    public static void main(String[] args) throws Exception {
        System.out.println("----------服务端启动------------");
        //1.创建ServerSocket对象,同时为服务器注册端口
        ServerSocket serverSocket=new ServerSocket(8888);
        while (true) {
            //2.使用serversocket对象,调用accept方法,等待客户端连接请求
            Socket socket=serverSocket.accept();
            //把上线的Socket对象存入集合中
            onListSocket.add(socket);
            //获取IP地址
            System.out.println(socket.getRemoteSocketAddress()+"---------上线---------");
            //3.把这个客户端对应的socket通信管道,交给一个独立的线程负责处理
            new ServerRraderThread(socket).start();

        }

    }
}
复制代码
复制代码
package Karl.Demo.Test;

import java.io.*;
import java.net.Socket;

public class ServerRraderThread extends Thread{
    //定义一个socket
    private Socket socket;
    //定义一个有参构造器,把获取来的数据交给本接口的socket
    public ServerRraderThread(Socket socket){
        this.socket=socket;
    }
    //重写run方法
    @Override
    public void run() {
        try {
            //用本接口socket获取到的数据交给字节输入流is
            InputStream is=socket.getInputStream();
            //把低级字节输入流is包装成数据输入流dis
            DataInputStream dis=new DataInputStream(is);
            //把读取数据放入死循环
            while (true) {
                try {
                    //用数据输入流方法读取数据交给String定义的msg
                    String msg=dis.readUTF();
                    //打印
                    System.out.println(msg);
                    //把数据msg传给sendMsgToAll方法,用来实现发送给全部客户端
                    sendMsgToAll(msg);
                } catch (IOException e) {
                    //获取关闭服务器的IP
                    System.out.println(socket.getRemoteSocketAddress()+"-------离线-----");
                    //把下线的Socket对象从集合中删除
                    Server.onListSocket.remove(socket);
                    //释放资源
                    socket.close();
                    dis.close();
                    break;
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    //创建方法用来发送数据
    private void sendMsgToAll(String msg) throws IOException {
        //遍历所有在线Socket客户端
        for (Socket socket1 : Server.onListSocket) {
            //把遍历到的客户端管道赋值给低级字节输出流os
            OutputStream os=socket1.getOutputStream();
            //把低级字节输出流包装成数据输出流dos
            DataOutputStream dos=new DataOutputStream(os);
            //用数据输出流dos的方法write给遍历到的客户端管道发送数据
            dos.writeUTF(msg);
            //IO流方法刷新,防止数据发送不出去
            dos.flush();
        }
    }
}
复制代码
复制代码
package Karl.Demo.Test;

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

public class ClentReaerThread extends Thread{
    //定义一个socket
    private Socket socket;
    //定义一个有参构造器,把获取来的数据交给本接口的socket
    public ClentReaerThread(Socket socket) {
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            //用本接口socket获取到的数据交给字节输入流is
            InputStream is=socket.getInputStream();
            //把低级字节输入流is包装成数据输入流dis
            DataInputStream dis=new DataInputStream(is);
            //把读取数据放入死循环
            while (true) {
                try {
                    //用数据输入流方法读取数据交给String定义的msg
                    String msg=dis.readUTF();
                    //打印
                    System.out.println(msg);
                } catch (IOException e) {
                    //获取关闭服务器的IP
                    System.out.println(socket.getRemoteSocketAddress()+"-------本机离线-----");
                    //释放资源
                    socket.close();
                    dis.close();
                    break;
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
复制代码

 

posted @   Karlshell  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示