0%

Java Socket通讯

Java ServerSocket与Socket交互

ServerSocket与Socket的区别

ServerSocket

ServerSocket对象可以监听一个固定的端口,但不能主动发起连接。

  • 创建ServerSocket
    1
    2
    3
    4
    ServerSocket() throws IOException;
    ServerSocket(int port) throws IOException;
    ServerSocket(int port, int backlog) throws IOException;
    ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException;
    通过构造函数,可以确定监听端口(port)**、客户端连接请求的队列长度(backlog)、服务端绑定IP(bindAddr)**。

如果端口被占用或者没有权限使用某些端口会抛出BindException错误。譬如1~1023的端口需要管理员才拥有权限绑定。

如果设置端口为0,则系统会自动为其分配一个端口。

  • 监听端口

    1
    Socket client = serverSocket.accept();

    accept()函数可以使Server端的程序处于等待状态,程序将一直阻塞直到捕捉到一个来自Client端的请求,并返回一个用于与该Client通信的Socket对象。此后Server程序只要向这个Socket对象读写数据,就可以实现向远端的Client读写数据。结束监听时。

  • 关闭ServerSocket

    1
    serverSocket.close();

    在关闭ServerSocket后,将释放其绑定的端口。

Socket

用于发起Socket连接,并且是通讯的数据通道。

  • 创建Socket

    1
    2
    3
    4
    5
    Socket();
    Socket(InetAddress address, int port) throws UnknownHostException, IOException;
    Socket(InetAddress address, int port, InetAddress localAddress, int localPort)throws IOException;
    Socket(String host, int port)throws UnknownHostException, IOException;
    Socket(String host, int port, InetAddress localAddress, int localPort)throws IOException;

    通过构造函数可以确定目的主机IP(host)**、目的主机端口(port)、本地IP(localAddress)、本地端口(localPort)**。

  • Socket常用方法

    1
    2
    3
    4
    5
    6
    getInetAddress();       //远程服务端的IP地址
    getPort(); //远程服务端的端口
    getLocalAddress(); //本地客户端的IP地址
    getLocalPort(); //本地客户端的端口
    getInputStream(); //获得输入流
    getOutStream(); //获得输出流
  • Socket状态

    1
    2
    3
    isClosed();     //连接是否已关闭,若关闭,返回true;否则返回false
    isConnect(); //如果曾经连接过,返回true;否则返回false
    isBound(); //如果Socket已经与本地一个端口绑定,返回true;否则返回false

注意:在发送和接收数据后,需要调用分别调用shutdownOutput()和shutdownInput(),告诉对方输入输出已经结束。

服务端设计方法

服务器端设置通常有两种方式:单线程方式和多线程方式。在Web服务器中,多线程方式更常见。

多线程方式结构通常如下:

1
2
3
4
5
6
7
8
9
10
11
12
public void service(){
while(true){
Socket socket=null;
try{
socket=serverSocket.accept(); //主线程获取客户端连接
Thread workThread = new Thread(new Handler(socket)); //创建线程
workThread.start(); //启动线程
}catch(Exception e){
e.printStackTrace();
}
}
}

在多线程的管理上,特别是实际生产环境中,通常使用线程池的方式来实现。

参考资料

  1. [Java]Socket和ServerSocket学习笔记
  2. Java Socket 编程之Socket与ServerSocket的区别