栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

建立客户端和服务端互连简单的聊天操作

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

建立客户端和服务端互连简单的聊天操作

服务端:

package JAVA_API.num18_socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


public class Server {
    
    private ServerSocket serverSocket ;

    
    //建一个集合用来存放通过流写出给的客户数量,这个集合应是一个线程安全的.
    private List allOutput = Collections.synchronizedList(new ArrayList<>());

    //进行服务端的初始化:
    public Server(){
        try {
            System.out.println("正在启动服务端...");
            
            //初始化时给成员变量赋值,在()里填入数字申请端口号,用来连接服务器
            //IllegalArgumentException: Port value out of range: 65536
            //serverSocket = new ServerSocket(65536);
            serverSocket = new ServerSocket(5050);
            System.out.println("服务端启动完毕!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void start() {
        try {
            
                while (true) {
                    System.out.println("等待客户端连接...");
                    //然后在main方法里调用方法,先启服务端,在启动客户端,accept()获取到的socket的返回值是连接当前服务端的客户端的socket。客户端的socket是Output来的。
                    Socket socket = serverSocket.accept();//用来监听
                    System.out.println("一个客户端连接了...");
                    //启动一个线程来负责与客户端交互的操作:
                    //1.创建线程任务,传入的参数就是监听到的Socket,
                    ClientHandler handler = new ClientHandler(socket);
                    //2.创建一个线程并执行该任务
                    Thread thread1 =  new Thread(handler);
                    //3.启动线程
                    thread1.start();
                }
            } catch(IOException e){
                e.printStackTrace();
            }
        }

        
        //写一个内部类来定义任务
        private class ClientHandler implements Runnable {
            //内部类可以有成员方法和变量
            //声明一个成员变量和构造方法
            private Socket socket;
            private String host;//当前线程处理的客户端的地址信息

            //通过传入的socket获取客户端的信息。
            public ClientHandler(Socket socket){
                this.socket = socket;
                //通过socket获取远端计算机地址信息(对于服务器而言,远端就是客户端),地址可以用来拼上谁谁说的话
                //获取客户端地址就是start()方法中监听到的socket即是客户端ip及端口,
                host = socket.getInetAddress().getHostAddress();
            }
            @Override
            public void run() {
                //将pw放在这里是为了能在finally中看到并处理
                PrintWriter pw = null;
                //socket能获取的只有字节流
                try {
                    
                    InputStream inputstream = socket.getInputStream();
                    //想要读,先转换
                    InputStreamReader isr = new InputStreamReader(inputstream,"UTF-8");
                    BufferedReader br = new BufferedReader(isr);

                    //用这个流来写出数据给客户端
                    pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),"UTF-8")),true);
                    
                    allOutput.add(pw);
                    //host是客户地址,allOutput.size()客户上线人数
                    System.out.println(host + "上线了,当前的在线人数:" + allOutput.size());
                    //调用发送消息的方法把消息发送给所有客户
                    sendMessage(host + "上线了,当前的在线人数:" + allOutput.size());
                    String line ;
                    while((line = br.readLine()) != null){

                        //host是读到的客户端地址,读到的内容是line
                        System.out.println(host + "说:" + line);

                        //将消息回复给所有的客户端,想要实现群发的效果,可以把写出到这一句放到集合,需要把客户端放到集合里
                        //pw.println(line);不能实现群发
                        //将客户输入的信息发给所有用户
                        sendMessage(host + "说:" + line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    //处理客户端断开后的操作
                    //1.从集合中移除
                    allOutput.remove(pw);
                    //移除之后给一个下线的通知
                    //host是客户地址,allOutput.size()客户上线人数
                    //2.广播下线通知
                    System.out.println(host + "下线了,当前的在线人数:" + allOutput.size());
                    try {
                        //3.关闭socket释放资源
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            //发送消息的方法
            
            private void sendMessage(String message){
                
                allOutput.forEach(pw -> pw.println(message));
              
            }
        }

    //main方法用于测试
    public static void main(String[] args) {
        Server server = new Server();
        server.start();
    }
}

客户端:

package JAVA_API.num18_socket;

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


public class Client {
    
    private Socket socket;
    
    public Client(){
        
        try {
            System.out.println("正在连接服务器...");
            socket = new Socket("192.168.43.196",5050);
            System.out.println("成功连接服务器!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    
    public void start(){
        //在写之前也需要
        //客户端启动后,先启动一个线程来读取服务端发送过来的消息
        ServerHandler handler = new ServerHandler();
        Thread thread = new Thread(handler);
        thread.start();
        

        //把流放在try()
        try(PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),"UTF-8")),true);
        ){
            //定义一个输出流用于写出数据到
            //OutputStream outputStream = socket.getOutputStream();
            //PrintWriter按行写出,BufferedWriter缓冲字符输出流加快写出数据,OutputStreamWriter将字符转换成字节,
            System.out.println("开始聊天吧!单独输入exit是退出!");
            Scanner scanner = new Scanner(System.in);
            while(true){
                String line = scanner.nextLine();
                if ("exit".equals(line)){
                    System.out.println("聊天结束");
                    break;
                }
                //将客户端控制台输入的信息发送到服务端,通过pw.Println()写出到服务端
                pw.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                socket.close();//最终和对方(服务器)断开连接
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    private class  ServerHandler implements Runnable {
        @Override
        public void run(){
            try (BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"))){
               //用来接收流读取出来的服务器发送过来的信息
                String message;
                //读取服务器发送过来的一行字符串
                while((message = br.readLine()) != null){
                    System.out.println(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    //测试
    public static void main(String[] args) {
        
        Client client = new Client();
        client.start();
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/275509.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号