zoukankan      html  css  js  c++  java
  • Socket 基础解析使用ServerSocket建立聊天服务器

    1.socket 简介

    Socket 又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求。ServerSocket 用于服务器端,Socket 是建立网络连接时使用的。在连接成功时,应用程序两端都会产生一个 Socket 实例,操作这个实例,完成所需的会话。

    2.ServerSocket 的建立与使用

    最简单的建立服务器ServerSocket

    复制代码
    public class MyServerSocket {
        
        public static void main(String[] args) {
            try {
                //1-65535 监听12345端口
                ServerSocket serverSocket = new ServerSocket(12345);
                //监听客户端链接,调用accept()方法 accept方法是一个阻塞的方法,会阻塞当前线程
                Socket socket = serverSocket.accept();
                //客户端有请求时,弹出提示框
                JOptionPane.showMessageDialog(null, "有客户链接到了本机的12345端口");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    复制代码

    运行该代码,会发现程序阻塞在serverSocket.accept()处,打开浏览器请求127.0.0.1:12345  会有弹窗,程序结束

    3.使用 ServerSocket 建立聊天服务器-1

    上述方法是不合理的,因为accept()方法会造成程序阻塞,这样,主线程就会被阻塞,对于阻塞的代码,需要放置到独立线程中,修改如下

    public class MyServerSocket {
        public static void main(String[] args) {
            new ServerListener().start();
        }
    }

    监听链接的线程

    复制代码
    /**
     * 监听连接的线程
     */
    public class ServerListener extends Thread{
        @Override
        public void run() {
            try {
                //1-65535 监听12345端口
                ServerSocket serverSocket = new ServerSocket(12345);
                //监听客户端链接,调用accept()方法 accept方法是一个阻塞的方法,会阻塞当前线程
                
                //每当有一个客户端连接到当前的serversocket就会返回一个新的socket对象,所以当有多个的时候
                //就要创建一个while循环来监听来自客户端的链接
                while (true) {//true,让他一直处于循环,不会结束
                    Socket socket = serverSocket.accept();
                    //客户端有请求时,弹出提示框
                    JOptionPane.showMessageDialog(null, "有客户链接到了本机的12345端口");
                    //由于每个socket又要与独立的客户端进行通讯,所以将socket传递给新的线程
                    new ChatSocket(socket).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    }
    复制代码

    用于通讯的线程

    复制代码
    /**
     * 创建用于socket通信的线程
     */
    public class ChatSocket extends Thread {
        
        Socket socket;//本地需要有socket来接受传入的s值
        
        public ChatSocket(Socket s){
            this.socket=s;
        }
        
        public void out(String out){
            try {
                // 执行数据的输出和相关功能的包装
                socket.getOutputStream().write(out.getBytes("UTF-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        @Override
        public void run() {
            int count = 0;
            while (true) {
                count++;
                out("loop:"+count);
                try {
                    sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    复制代码

    此时一个线程版的socket通信就算结束了,打开cmd 输入telnet localhost 12345会有惊喜哦

    这种惊喜('telnet' 不是内部或外部命令,也不是可运行的程序)的自行百度

    此时可以同时打开多个cmd 效果相同

    4.使用 ServerSocket 建立聊天服务器-2

    以上是一个简单的socket聊天服务器,但是当前的服务器只有向客户端发送数据的功能,并没有从客户端读取数据的功能!

    每个ChatSocket线程都是独立的,不能相互共同数据,建立ChatManager沟通所有数据,代码修改如下:

    public class MyServerSocket {
        public static void main(String[] args) {
            new ServerListener().start();
        }
    }

    监听链接的线程

    复制代码
    /**
     * 监听连接的线程
     */
    public class ServerListener extends Thread{
        @Override
        public void run() {
            try {
                //1-65535 监听12345端口
                ServerSocket serverSocket = new ServerSocket(12345);
                //监听客户端链接,调用accept()方法 accept方法是一个阻塞的方法,会阻塞当前线程
                
                //每当有一个客户端连接到当前的serversocket就会返回一个新的socket对象,所以当有多个的时候
                //就要创建一个while循环来监听来自客户端的链接
                while (true) {//true,让他一直处于循环,不会结束
                    Socket socket = serverSocket.accept();
                    //客户端有请求时,弹出提示框
                    JOptionPane.showMessageDialog(null, "有客户链接到了本机的12345端口");
                    //由于每个socket又要与独立的客户端进行通讯,所以将socket传递给新的线程
                    ChatSocket cs = new ChatSocket(socket);
                    cs.start();
                    ChatManager.getChatManager().add(cs);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    }
    复制代码

    创建用于socket通信的线程

    复制代码
    /**
     * 创建用于socket通信的线程
     */
    public class ChatSocket extends Thread {
        
        Socket socket;//本地需要有socket来接受传入的s值
        
        public ChatSocket(Socket s){
            this.socket=s;
        }
        
        public void out(String out){
            try {
                // 执行数据的输出和相关功能的包装
                socket.getOutputStream().write(out.getBytes("UTF-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        @Override
        public void run() {//run方法中加入接收数据的功能
            try {
                BufferedReader br = new BufferedReader(
                        new InputStreamReader(
                                socket.getInputStream(),"UTF-8"));
                String line = null;
                while ((line = br.readLine())!=null) {//客户端的数据
                    //发给聊天室的所有人
                    ChatManager.getChatManager().publish(this, line);
                }
                br.close();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    复制代码

    聊天管理类

    复制代码
    /**
     * 聊天管理类
     */
    public class ChatManager {
    
        //单例化该ChatManager
        private ChatManager(){}
        private static final ChatManager cm = new ChatManager();
        public static ChatManager getChatManager(){
            return cm;
        }
        Vector<ChatSocket> vector = new Vector<ChatSocket>();
        
        public void add(ChatSocket cs){
            vector.add(cs);
        }
        
        public void publish(ChatSocket cs,String out){
            for(int i=0;i<vector.size();i++){
                ChatSocket cschatSocket = vector.get(i);
                if(!cs.equals(cschatSocket)){//发送消息的对象不接受消息本身
                    cschatSocket.out(out);
                }
            }
        }
    }
    复制代码

    打开多个cmd,实现聊天功能,无论在哪个终端发,都能接收到消息

     

  • 相关阅读:
    suse linux编译安装GCC报错
    suse linux 编译安装Apache时报“APR NOT FOUND”的解决方法
    LoadRunner监控Windows和Linux常见问题
    LR报-27727错误解决办法
    主机在virtualbox在NAT方式SSH访问
    清除hao123浏览器劫持小尾巴病毒
    在CentOS上,Servlet出现java.lang.NoClassDefFoundError
    构建第一个SSH的maven项目
    关于Oracle数据库sys用户登入的解惑
    ip route-static 命令的参数
  • 原文地址:https://www.cnblogs.com/android-blogs/p/4974945.html
Copyright © 2011-2022 走看看