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,实现聊天功能,无论在哪个终端发,都能接收到消息

 

 

posted on 2015-11-18 16:32  Sun‘刺眼的博客  阅读(351)  评论(0编辑  收藏  举报

导航