zoukankan      html  css  js  c++  java
  • BIO实现聊天室

    网络

    在物理网络的基础上,建立抽象的连接

    win + r, 输入 cmd

    输入命令:

    ipconfig

    如果ping不通,要关闭防火墙

    开始---搜索防火墙

    Socket 通信

    Socket - 插头

    Socket - 网络套接字

    通过 ip 地址,两台主机可以互相找到对象

    在两台主机上,各选择一个端口号

    端口是独占的,0到1024是一些常见服务的默认端口---http 80--https 443--ftp 21...5万以后,是系统保留端口用,来自动分配

    我们选择端口要选择 1024到5万之间的端口号 

    服务器端

    被动等待客户端发起连接

    ServerSocket 在服务器端,选择一个端口号, 在指定端口上等待客户端发起连接

    ServerSocket ss = new ServerSocket(8000);

    等待客户端发起连接,建立连接通道,并返回连接通道的服务器端插头对象

    Socket s = ss.accept();

    客户端

    主动去连接服务器

    Socket s = new Socket(ip, port);

    取出双向的流

    InputStream in = s.getInputStream();
    
    OutputStream out = s.getOutputStream();

    超时

    socket.setSoTimeout(毫秒值)

    设置接收数据,等待超时时长,超时会出现 SocketTimeoutException

    实例:

    package demo;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class Server1 {
    
    public static void main(String[] args) throws Exception {
        ServerSocket ss = new ServerSocket(8000);
        System.out.println(
         "服务已经在 8000 端口上启动");
        //暂停等待客户端发起连接
        System.out.println("等待客户端连接");
        Socket s = ss.accept();
        System.out.println("客户端已连接");
        //从插头对象,获取输入流和输出流
        InputStream in = s.getInputStream();
        OutputStream out = s.getOutputStream();
        /*
         * 通信协议,通信流程,数据格式
         *
         *     服务器端:
         *       1. 接收 "hello"
         *       2. 发送 "world"
         */
        for (int i = 0; i < 5; i++) {
            char c = (char) in.read();
            System.out.print(c);
        }
        out.write("world".getBytes());
        out.flush(); //刷出内存缓存 
        s.close();//断开连接
        ss.close();//停止服务,释放端口
    }
    }

    Client

    package demo;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.Socket;
    
    public class Client1 {
    public static void main(String[] args) throws Exception {
        Socket s = new Socket("旁边同学ip", 8000);
        InputStream in = s.getInputStream();
        OutputStream out = s.getOutputStream();
        /* 客户端:
         *    1. 发送 "hello"
         *    2. 接收 "world"
         */
        out.write("hello".getBytes());
        out.flush(); //刷出内存缓存
        for (int i = 0; i < 5; i++) {
            char c = (char) in.read();
            System.out.print(c);
        }
        s.close();
    }
    }

    阻塞操作

    ss.accept()

    暂停,等待客户端发起连接

    in.read()

    对方不发送数据,暂停,死等数据

    服务器端的线程模型

    回声

    客户端发送到服务器的数据,原封不动的发回客户端

    EchoServer

    package demo;
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
     
    public class EchoServer {
    public void launch() {
        new Thread() {
            @Override
            public void run() {
               try {
                  ServerSocket ss = new ServerSocket(8000);
                  System.out.println("服务已在 8000 端口上启动");
                  while(true) {
                     System.out.println("等待下一个客户端连接");
                     Socket s = ss.accept();
                     System.out.println("客户端已连接");
                     TongXinThread t = new TongXinThread(s);
                     t.start();
                  }
               } catch (Exception e) {
                  System.out.println(
                   "无法在 8000 端口上启动服务,或服务已停止");
               }
            }
        }.start();
    }
    class TongXinThread extends Thread {
        Socket s;
        public TongXinThread(Socket s) {
            this.s = s;
        }
        @Override
        public void run() {
            /*
             * 通信协议,流程和格式
             * UTF-8编码的字符串,
             * 每段字符串末尾添加换行
             *
             * BR--ISR--网络输入流
             * PW--OSW--网络输出流
             */
            try {
               BufferedReader in =
                new BufferedReader(
                new InputStreamReader(
                s.getInputStream(), "UTF-8"));
               PrintWriter out =
                new PrintWriter(
                new OutputStreamWriter(
                s.getOutputStream(),"UTF-8"));
               String line;
               while((line = in.readLine()) != null) {
                  out.println(line);
                  out.flush();
               }
               //断开
            } catch (Exception e) {
               //断开
            }    
            System.out.println("一个客户端端已断开");     
        }
    }
    
    
    
    public static void main(String[] args) {
    
        EchoServer s = new EchoServer();
    
        s.launch();
    
    }
    
    }

    EchoClient

    package demo;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.io.UnsupportedEncodingException;
    import java.net.Socket;
    import java.util.Scanner;
    
    public class EchoClient {
    public static void main(String[] args) throws Exception {
        Socket s = new Socket("找一个人启动服务器", 8000);
        BufferedReader in =
         new BufferedReader(
         new InputStreamReader(
         s.getInputStream(), "UTF-8"));
        PrintWriter out =
         new PrintWriter(
         new OutputStreamWriter(
         s.getOutputStream(),"UTF-8"));   
        while(true) {
            System.out.print("输入:");
            String str = new Scanner(System.in).nextLine();
            out.println(str);
            out.flush();
            String echo = in.readLine();
            System.out.println("回声:"+echo);
            System.out.println("-----------------");
        }
    }
    }

    聊天室

    ChatServer

    package demo;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.ArrayList;
     
    public class ChatServer {
    private ArrayList<TongXinThread> list =
            new ArrayList<>();
    public void launch() {
        //启动服务线程
        new Thread() {
            @Override
            public void run() {
               try {
                  ServerSocket ss = new ServerSocket(8000);
                  System.out.println("聊天室服务器已启动");
                  while(true) {
                     Socket s = ss.accept();
                     TongXinThread t =
                      new TongXinThread(s);
                     t.start();
                  }
               } catch (Exception e) {
                  System.out.println(
                   "服务无法在 8000 端口上启动,或服务已经停止");
               }
            }
        }.start();
    }
    
    class TongXinThread extends Thread {
        Socket s;
        BufferedReader in;
        PrintWriter out;
        private String name;
        public TongXinThread(Socket s) {
            this.s = s;
        }
        public void send(String msg) {
            out.println(msg);
            out.flush();
        }
        public void sendAll(String msg) {
            synchronized (list) {
               for (TongXinThread t : list) {
                  t.send(msg);
               }
            }
        }
        @Override
        public void run() {
            try {
               //UTF-8, 换行
               in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8"));
               out = new PrintWriter(new OutputStreamWriter(s.getOutputStream(),"UTF-8"));            
               //接收客户端的昵称
               this.name = in.readLine();
               //把当前通信线程实例,加入集合
               synchronized (list) {
                  list.add(this);
               }
               //发送欢迎信息
               send("欢迎进入激情聊天室");
               //群发上线消息
               sendAll(name+"进入了聊天室,在线人数:"+list.size());     
               String line;
               while((line = in.readLine()) != null) {
                  sendAll(name+"说:"+line);
               }
               //断开
            } catch (Exception e) {
               //断开
            }
            //删除当前通信线程实例
            synchronized (list) {
               list.remove(this);
            }
            //群发离线消息
            sendAll(name+"离开了聊天室,在线人数:"+list.size());
        }
    }
    
    
    
    
    
    public static void main(String[] args) {
    
        ChatServer s = new ChatServer();
    
        s.launch();
    
    }
    
    }

    ChatClient

    package demo;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.net.Socket;
    import java.util.LinkedList;
    import java.util.Scanner;
     
    public class ChatClient {
    private Socket s;
    private BufferedReader in;
    private PrintWriter out;
    private String name;
    private LinkedList<String> list = new LinkedList<>();
    private boolean flag; //开关
    
    public void launch() {
        try {
            s = new Socket("192.168.21.61", 8000);
            in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8"));
            out = new PrintWriter(new OutputStreamWriter(s.getOutputStream(),"UTF-8"));              
            //昵称
            System.out.print("起一个昵称: ");
            name = new Scanner(System.in).nextLine();
            out.println(name);
            out.flush();      
            //接收线程
            new Thread() {
               @Override
               public void run() {
                  receive();
               }
            }.start();
            //输入线程
            new Thread() {
              @Override
               public void run() {
                  input();
               }
            }.start();     
            //打印线程
            new Thread() {
               @Override
               public void run() {
                  print();
               }
            }.start();    
        } catch (Exception e) {
            System.out.println("无法连接聊天室服务器");
            e.printStackTrace();
        }
    }
    protected void print() {
        while(true) {
            synchronized (list) {
               while (list.isEmpty() || flag) {
                  try {
                     list.wait();
                } catch (InterruptedException e) {
               }
              }
               String msg = list.removeFirst();
               System.out.println(msg);
            }
        }
    } 
    protected void input() {
        System.out.println("按回车输入聊天内容"); 
        while(true) {
            new Scanner(System.in).nextLine();
            flag = true;//打开开关      
            System.out.print("输入聊天内容:");
            String s = new Scanner(System.in).nextLine();
            out.println(s);
            out.flush();    
            flag = false;//关闭开关
            //通知打印线程可以继续打印
            synchronized (list) {
            list.notify();
            }
        }
    }
    protected void receive() {
        try {
            String line;
            while((line = in.readLine()) != null) {
               synchronized (list) {
                  list.add(line);
                  //通知打印线程已经有数据可以打印了
                  list.notify();
              }
            }
        } catch (Exception e) {
        }
        System.out.println("已经与服务器断开连接");
    }
    public static void main(String[] args) {
        ChatClient c = new ChatClient();
        c.launch();
    }
    }

  • 相关阅读:
    [FJOI 2016] 神秘数
    [SHOI 2017] 寿司餐厅
    [HAOI 2012] Road
    [HAOI 2012] 容易题
    [TJOI 2018] XOR
    [NOI 2011] 阿狸的打字机
    [ZJOI 2010] 排列计数
    [TJOI2016 & HEOI2016] 字符串
    [HNOI 2011] 数学作业
    【NTT】loj#6261. 一个人的高三楼
  • 原文地址:https://www.cnblogs.com/yunianzeng/p/12109804.html
Copyright © 2011-2022 走看看