JAVASocket实现聊天室「建议收藏」

2022-07-02 16:15:00 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

JAVASocket实现聊天室

文章目录
  • JAVASocket实现聊天室
  • Sokcet是什么
  • JAVA SOCKET编程中的两个重要对象
    • ServerSocket
      • 构造方法
      • accept
      • bind
      • close
    • Socket
      • 构造方法
      • getInputStream,getOutputStream
      • close
  • 聊天室实现
    • 服务端实现
    • 客户端实现
    • 读线程实现
    • 写线程实现
    • 运行结果

Sokcet是什么

socket本质上是两个端点之间的通信桥梁,两个端点相互连接,并且打开远程之间的网络IO,从而可以像对本地文件读写一样,JAVA对socket编程有着友好的支持,并且针对客户端和服务端抽象了不同的服务对象

JAVA SOCKET编程中的两个重要对象

JDK对Socket编程抽象了两个类ServerSocketSocket,分别封装了客户端和服务端的基本通信API

ServerSocket

JDK提供的服务端实现,主要用于监听服务端口,并且接受来自该端口的客户端请求,并且生成来自客户端的Socket对象。

几个重要的方法:

构造方法
  • ServerSocket()
  • ServerSocket(int port)
  • ServerSocket(int port,int backlog)
  • ServerSocket(int port,int backlog,InnetAddress bindAddr)

上述构造方法设计到大致三个参数,port(端口),backlog请求客户端队列最大长度,bindAddr,将要绑定的IP实现,如果不指定默认本地IP。

accept
代码语言:javascript复制
public Socket accept() throws IOException

accept方法主要是在开启端口监听之后接受一个客户端的连接请求,如果没有请求进来,那么accept方法会一直阻塞,直到一个客户端的请求进入,accept方法在接受一个客户端的请求之后,会生成一个客户端的Socket对象,这个对象封装了客户端的IO请求。

代码语言:javascript复制
Socket client = serverSocket.accept();
//对客户端的输入输出流
OutputStream outputStream= client.getOutputStream();
InputStream  inputStream = client.getInputStream();

服务端可通过这个Socket对象获取对客户端的输入流和输出流,这样服务端就可以读取到客户端发送来的的消息,并且可以向客户端发送消息

bind

bind方法是真正实现socket套接字绑定IP和端口的实现,默认在ServerSocket的构造方法中会进行调用。

代码语言:javascript复制
public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException { 
   
        ...
        try { 
   
            bind(new InetSocketAddress(bindAddr, port), backlog);
        } catch(SecurityException e) { 
   
            close();
            throw e;
        } catch(IOException e) { 
   
            close();
            throw e;
        }
}
close

当主动调用close方法后,服务器会释放当前绑定的端口,并且自动断开和所有客户端之间的连接,只有主动执行了ServerSocket的close()方法,isClosed()方法才返回true;否则,即使ServerSocket还没有和特定端口绑定,isClosed()方法也会返回false,这是因为服务端内部维护了一个closed变量,初始化为false,只有在调用了close方法才会将closed变量置为true

Socket

JDK提供的Socket套接字实现类,主要封装了端的IO操作,通过Socket对象我们可以实现对客户端及服务端的读写操作

构造方法
代码语言:javascript复制
Socket(InetAddressaddress, int port);
Socket(InetAddress address,int port, boolean stream);
Socket(String host, intprot);
Socket(String host, intprot, boolean stream);
Socket(SocketImpl impl)
Socket(String host, intport, InetAddress localAddr, Socket(InetAddress address,int port, InetAddress localAddr, int localPort)
ServerSocket(int port);
ServerSocket(int port, intbacklog);
ServerSocket(int port, intbacklog, InetAddress bindAddr)

其中address、host和port分别是双向连接中另一方的IP地址、 主机名和端口号,stream指明socket是流socket还是数据报 socket,localPort表示本地主机的端口号,localAddr和bindAddr是本地机器的地址(ServerSocket的主机地 址),impl是socket的父类,既可以用来创建serverSocket又可以用来创建Socket。count则表示服务端所能支持的最大连接数。

Socket(String host, intprot)

常用的构造方法默认指定host和port,表示要建立的远程连接的服务端IP和端口,在服务端开启端口监听之后,客户端可以得到一个连接到服务端的Socket对象,同时服务端也会得到一个连接到客户端的Socket对象,这样双方可基于Socket实现双向通信,发送并且接受消息

getInputStream,getOutputStream

获取对应端的输入输出流,当双方建立连接后,双方互相持有封装了对方IO操作的Sokcet对象,通过Socket对象获取对应的输入输出流实现双向通信。

close

当客户端的Socket关闭连接时,服务端与客户端的连接自动关闭,但是服务端会继续监听端口,等待新的连接进来。

当服务端的Sokcet关闭连接时,服务端与所有客户端的连接将全部断开,并且释放对应监听接口

聊天室实现

服务端实现

监听端口,调用accept方法等待客户端请求,另外新起两个线程分别针对客户端的读写进行处理

代码语言:javascript复制
public class Server { 
   

    public static final Integer port =80;

    public static void main(String[] args) throws IOException { 
   
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("服务端监听 " port " 端口成功!,等待客户端连接");
        while (true){ 
   
            Socket client = serverSocket.accept();
            System.out.println("一个新的客户端进来了");
            new WriteHelper(client.getOutputStream(),"连接客户端成功!,可以畅所欲言了").start();
            new PrintHelper(client.getInputStream(),"服务端").start();
        }
    }


}
客户端实现

绑定ip和端口,并且启动两个线程分别处理来自服务端的读写

代码语言:javascript复制
public class Client { 
   

    public static void main(String[] args) throws IOException, InterruptedException { 
   
        Socket socket = new Socket("127.0.0.1", 80);
        new WriteHelper(socket.getOutputStream(),"连接服务端成功!,可以畅所欲言了").start();
        new PrintHelper(socket.getInputStream(),"客户端").start();
    }
}

针对Socket的输入输出流实现单独线程处理,读写不互相收影响

读线程实现

主要针对Sokcet对象的输入流进行单独处理

代码语言:javascript复制
public class PrintHelper extends Thread{ 
   

    private InputStream inputStream;
    private String type;

    public PrintHelper(InputStream inputStream,String type) { 
   
        this.inputStream=inputStream;
        this.type=type;
    }

    public void run() { 
   
        byte[] bytes = new byte[1024];
        int length;
        try { 
   
            while (true){ 
   
                if (((length=inputStream.read(bytes))>1)){ 
   
                    String s = new String(bytes, 0, length);
                    LocalDateTime nowLocalDate = LocalDateTime.now();
                    String time = nowLocalDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                    System.out.println(" " time " " type " : " s);
                    System.out.println("____________________________________________");
                }
            }
        } catch (IOException e) { 
   
            e.printStackTrace();
        }
    }

}
写线程实现

主要针对Socket对象的输出流进行单独处理,

代码语言:javascript复制
public class WriteHelper extends Thread{ 
   

        private OutputStream outputStream;

        public WriteHelper(OutputStream outputStream,String message) { 
   
            System.out.println(message);
            System.out.println("============================");
            this.outputStream=outputStream;
        }

        public void run() { 
   
            Scanner scanner = new Scanner(System.in);
            while(true){ 
   
                String next = scanner.next();
                try { 
   
                    outputStream.write(next.getBytes());
                    outputStream.flush();
                } catch (IOException e) { 
   
                    e.printStackTrace();
                }
            }
        }
}
运行结果

需要先启动服务端,开启端口监听,再启动客户端,实现IP加端口的连接

启动服务端

客户端连接

客户端发送消息

服务端收到消息

服务端回复消息

客户端收到消息

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/148336.html原文链接:https://javaforall.cn

0 人点赞