TCP通信——端口转发(重点内容)

实现多人群聊

Client(客户端)建立通信

package com.zz.tcp.case1;

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

public class Client {
    public static void main(String args[]) throws Exception {
        //1.创建Socket对象,并同时请求与服务端程序连接
        Socket socket = new Socket("127.0.0.1", 8888);

        //创建一个独立的线程,负责随机从socket中接收服务端的发送过来的消息
        new ClientReaderThread(socket).start();

        //2.从socket通信管道中的到一个字节输出流,用来发送数据
        OutputStream os = socket.getOutputStream();

        //将低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);

        Scanner sc = new Scanner(System.in);
        while(true){
            System.out.println("请说:");
            String msg = sc.nextLine();

            //一旦用户输入了exit就退出客户端程序
            if("exit".equals(msg)){
                System.out.println("欢迎您下次光临!");
                dos.close();
                socket.close();
                break;
            }

            //4.开始写数据出去
            dos.writeUTF(msg);
            //5.刷新数据,防止数据留在管道
            dos.flush();
        }
    }
}

ClientReaderThread(服务端线程类)——实现接收服务端转发的消息

package com.zz.tcp.case1;

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

public class ClientReaderThread extends Thread{
    private Socket socket;
    public ClientReaderThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            InputStream is = socket.getInputStream();
            DataInputStream dis = new DataInputStream(is);
            while (true) {
                try {
                    String msg = dis.readUTF();
                    System.out.println(msg);
                    //把这个消息发送给全部客户端进行接收
                    sendMsgToAll(msg);
                } catch (Exception e) {
                    System.out.println("自己下线了" + socket.getRemoteSocketAddress());
                    dis.close();
                    socket.close();
                    break;
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void sendMsgToAll(String msg) throws IOException {
        //发送给全部在线的socket的管道接收
        for (Socket onLineSocket: Server.onLineSockets) {
            OutputStream os = onLineSocket.getOutputStream();
            DataOutputStream dos = new DataOutputStream(os);

            dos.writeUTF(msg);
            dos.flush();
        }
    }
}

Server(服务端)负责接收客户端的消息,通过8888端口建立连接

package com.zz.tcp.case1;

import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class Server {
    public static List<Socket> onLineSockets = new ArrayList <>();
    public static void main(String args[]) throws Exception{
        System.out.println("========服务端启动========");
        //1.创建ServerSocket的对象,调用一个accept方法,等待客户端的连接请求
        ServerSocket serverSocket = new ServerSocket(8888);
        while (true){
            //2.使用ServerSocket对象,调用一个accept方法,等待客户端的连接请求
            Socket socket = serverSocket.accept();
            onLineSockets.add(socket);
            System.out.println("有人上线了" + socket.getRemoteSocketAddress());
            //3.把这个客户端对应的socket通信管道,交给一个独立的线程复制处理
            new ServerReaderThread(socket).start();
        }

    }
}

ServerReaderThread(客户端线程类)——负责接受客户端发的消息,然后转发给其他客户端

package com.zz.tcp.case1;

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

public class ServerReaderThread extends Thread{
    private Socket socket;
    public ServerReaderThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            InputStream is = socket.getInputStream();
            DataInputStream dis = new DataInputStream(is);
            while (true) {
                try {
                    String msg = dis.readUTF();
                    System.out.println(msg);
                    //把这个消息发送给全部客户端进行接收
                    sendMsgToAll(msg);
                } catch (Exception e) {
                    System.out.println("有人下线了" + socket.getRemoteSocketAddress());
                    Server.onLineSockets.remove(socket);
                    dis.close();
                    socket.close();
                    break;
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void sendMsgToAll(String msg) throws IOException {
        //发送给全部在线的socket的管道接收
        for (Socket onLineSocket: Server.onLineSockets) {
            OutputStream os = onLineSocket.getOutputStream();
            DataOutputStream dos = new DataOutputStream(os);

            dos.writeUTF(msg);
            dos.flush();
        }
    }
}

相关推荐

  1. TCP和udp能使用同一个端口通讯

    2024-03-31 05:38:10       27 阅读
  2. <span style='color:red;'>TCP</span><span style='color:red;'>通信</span>

    TCP通信

    2024-03-31 05:38:10      30 阅读
  3. docker 开启 tcp 端口

    2024-03-31 05:38:10       31 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-31 05:38:10       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-31 05:38:10       101 阅读
  3. 在Django里面运行非项目文件

    2024-03-31 05:38:10       82 阅读
  4. Python语言-面向对象

    2024-03-31 05:38:10       91 阅读

热门阅读

  1. c语言-生成随机数、获取当前年月日时分秒

    2024-03-31 05:38:10       44 阅读
  2. GFW不起作用

    2024-03-31 05:38:10       37 阅读
  3. Redis的基础命令详解

    2024-03-31 05:38:10       38 阅读
  4. IntelliJ IDEA 插件开发中监听用户的保存事件

    2024-03-31 05:38:10       32 阅读
  5. c入门基础题(2)

    2024-03-31 05:38:10       37 阅读
  6. SQL注入(二)

    2024-03-31 05:38:10       42 阅读
  7. shell获取多个oracle库mysql库所有的表主键

    2024-03-31 05:38:10       40 阅读
  8. vue图片压缩

    2024-03-31 05:38:10       43 阅读
  9. RK3588平台开发系列讲解(开发环境搭建)

    2024-03-31 05:38:10       38 阅读
  10. springboot和spring的区别

    2024-03-31 05:38:10       35 阅读
  11. 预处理、编译、汇编、链接过程

    2024-03-31 05:38:10       37 阅读