网络编程5

TCP通信-群聊

Server

java 复制代码
package TCP3;

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> OnlineSockets = 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
            OnlineSockets.add(socket);

            //追踪客户端上限
            System.out.println("有人上线了:"+ socket.getRemoteSocketAddress());

            //3.把这个客户端对应的socket通信管道,交给一个独立的线程负责处理
            new ServerReaderTread(socket).start();
        }
    }
}

创建服务端及其端口后,使用死循环与多个客户端链接,然后再分配子进程去管理这个客户端发来的消息

ServerReadTread

java 复制代码
package TCP3;

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

public class ServerReaderTread extends Thread {

    //线程变量
    private Socket socket;

    //有参构造器
    public ServerReaderTread(Socket socket){
        this.socket = socket;
    }

    public void run(){
        //从socket通信管理中得到一个字节输入流
        try {
            InputStream is = socket.getInputStream();
            DataInputStream dis = new DataInputStream(is);
            while (true){
                try {
                    String msg = dis.readUTF();
                    System.out.println(msg);
                    //把这个消息发给全部客户端进行接收
                    sendMsgToAll(msg);
                } catch (IOException e) {
                    System.out.println("有人下线了:"+ socket.getRemoteSocketAddress());
                    //在在线Socket集合中删除对应端口
                    Server.OnlineSockets.remove(socket);
                    dis.close();
                    socket.close();
                    break;
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    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();

        }
    }
}

客户端每与服务端连接,就会生成这个对应的子进程来管理,将输入字节流转换为数据流后,将其打印,跟踪客户端是否下线,最后将消息转发给所有在线的socket管道

Client

java 复制代码
package TCP3;

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.创建Socket对象,并同时请求与服务端的连接
        Socket socket = new Socket("127.0.0.1",8888);

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

        //2.从socket通信管道中得到一个字节输出流,用来发数据给服务端程序
        OutputStream os = socket.getOutputStream();

        //3.把低级的字节输出流包装成数据输出流
        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);
            dos.flush();
        }
    }

}

创建客户端后,创建对应的客户端子进程用来接收信息,使用死循环不断将信息发送,

ClientReaderTread

java 复制代码
package TCP3;

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

public class ClientReaderTread extends Thread {
    //线程变量
    private Socket socket;

    //有参构造器
    public ClientReaderTread(Socket socket){
        this.socket = socket;
    }
    public void run(){
        try {
            InputStream is = socket.getInputStream();
            DataInputStream dis = new DataInputStream(is);
            while (true){
                try {
                    String msg = dis.readUTF();
                    System.out.println(msg);
                } catch (IOException e) {
                    System.out.println("自己下线了:"+ socket.getRemoteSocketAddress());
                    dis.close();
                    socket.close();
                    break;
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

也是从通信管道中获取这个信息输入流,然后将其打印出来

相关推荐
不可求~几秒前
C++ std::string_view 不是字符串:从悬空引用到安全用法
java·开发语言·c++
Lam Tang2 分钟前
APS 系列文章10
java·代理模式
考虑考虑42 分钟前
Excel导入时产生特殊字符处理
java·后端·java ee
Scabbards_1 小时前
面试Leetcode - Heap 堆
java·leetcode·面试
程序员清风2 小时前
专业再升级!程序员专属显示器明基RD280UG上手实测!
java·后端·面试
ryan_9962 小时前
MCP Transport 完整指南:stdio 与 Streamable HTTP 到底怎样传消息
网络·网络协议·http
Lam Tang3 小时前
APS 系列文章 08
java·代理模式
萧瑟余晖4 小时前
Java深入解析篇三十三之消息队列
java·开发语言
码匠许师傅4 小时前
【C++ 面试真题】聊聊 C++ 的序列容器
java·c++·面试
IT爱学堂4 小时前
尚硅谷Java+AI大模型应用开发革新版本 2025年3月
java·开发语言·人工智能