首页 > 代码库 > 【网络编程】Socket基础

【网络编程】Socket基础

Socket 通常称为“套接字”。Socket字面上的中文意思为“插座”。一台服务器可能会提供很多服务,每种服务对应一个Socket(也可以这么说,每个 Socket就是一个插座,客户若是需要哪种服务,就将插头插到相应的插座上面),而客户的“插头”也是一个Socket。Socket是应用层与 TCP/IP协议族通信的中间软件抽象层,它是一组接口。Socket把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接 口就是全部,让Socket去组织数据,以符合指定的协议。Socket用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过套接字向网络发出 请求或者应答网络请求。

Socket的基本操作包括:

  • 连接远程机器
  • 发送数据
  • 接收数据
  • 关闭连接
  • 绑定端口
  • 监听到达数据
  • 在绑定的端口上接受来自远程机器的连接

服 务器要和客户端通信,两者都要实例化一个Socket。服务器和客户端的Socket是不一样的,客户端可以实现连接远程机器、发送数据、接收数据、关闭 连接等,服务器还需要实现绑定端口,监听到达的数据,接受来自远程机器的连接。Android在包java.net里面提供了两个 类:ServerSocket和Socket,前者用于实例化服务器的Socket,后者用于实例化客户端的Socket。在连接成功时,应用程序两端都 会产生一个Socket实例,操作这个实例,完成客户端到服务器所需的会话。

接下来分析一些重要的Socket编程接口。首先是如何构造一个Socket,常用的构造客户端Socket的方法有以下几种。

  • Socket():创建一个新的未连接的Socket。
  • Socket(Proxy proxy):使用指定的代理类型创建一个新的未连接的Socket。
  • Socket(String dstName,int dstPort):使用指定的目标服务器的IP地址和目标服务器的端口号,创建一个新的Socket。
  • Socket(String dstName,int dstPort,InetAddress localAddress,int localPort):使用指定的目标主机、目标端口、本地地址和本地端口,创建一个新的Socket。
  • Socket(InetAddress dstAddress,int dstPort):使用指定的本地地址和本地端口,创建一个新的Socket。
  • Socket(InetAddress dstAddress,int dstPort,InetAddress localAddress,int localPort):使用指定的目标主机、目标端口、本地地址和本地端口,创建一个新的Socket。

其中,proxy为代理服务器地址,dstAddress为目标服务器IP地址,dstPort为目标服务器的端口号(因为服务器的每种服务都会绑定在一个端口上面),dstName为目标服务器的主机名。Socket构造函数代码举例如下所示:

// 第一个参数是目标服务器的IP地址,2012是目标服务器的端口号      Socket client=new Socket("192.168.1.23", 2012);   // 实例化一个Proxy,以该Proxy为参数,创建一个新的Socket Socket sock = new Socket(new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("test.domain.org", 2130)));  

注意 0~1023端口为系统保留,用户设定的端口号应该大于1023。

 

Socket

/**     * Gets an input stream to read data from this socket.     *     * @return the byte-oriented input stream.     * @throws IOException     *             if an error occurs while creating the input stream or the     *             socket is in an invalid state.     */    public InputStream getInputStream() throws IOException {        checkOpenAndCreate(false);        if (isInputShutdown()) {            throw new SocketException("Socket input is shutdown");        }        return impl.getInputStream();    }

  

    /**     * Gets an output stream to write data into this socket.     *     * @return the byte-oriented output stream.     * @throws IOException     *             if an error occurs while creating the output stream or the     *             socket is in an invalid state.     */    public OutputStream getOutputStream() throws IOException {        checkOpenAndCreate(false);        if (isOutputShutdown()) {            throw new SocketException("Socket output is shutdown");        }        return impl.getOutputStream();    }

  

    /**     * Closes the socket. It is not possible to reconnect or rebind to this     * socket thereafter which means a new socket instance has to be created.     *     * @throws IOException     *             if an error occurs while closing the socket.     */    public synchronized void close() throws IOException {        isClosed = true;        // RI compatibility: the RI returns the any address (but the original local port) after close.        localAddress = Inet4Address.ANY;        impl.close();    }

上面是构造Socket客户端的几种常用的方法,构造服务器端的ServerSocket的方法有以下几种。

  • ServerSocket():构造一个新的未绑定的ServerSocket。
  • ServerSocket(int port):构造一个新的ServerSocket实例并绑定到指定端口。如果port参数为0,端口将由操作系统自动分配,此时进入队列的数目将被设置为50。
  • ServerSocket(int port,int backlog):构造一个新的ServerSocket实例并绑定到指定端口,并且指定进入队列的数目。如果port参数为0,端口将由操作系统自动分配。
  • ServerSocket(int port,int backlog,InetAddress localAddress):构造一个新的ServerSocket实例并绑定到指定端口和指定的地址。如果localAddress参数为null,则 可以使用任意地址,如果port参数为0,端口将由操作系统自动分配。

下面举例说明ServerSocket的构建方法,代码如下所示:

// 2012表示服务器要监听的端口号        ServerSocket socketserver=new ServerSocket(2012);    

构造完ServerSocket之后,需要调用ServerSocket.accept()方法来等待客户端的请求(因为Socket都是绑定在端口上面 的,所以知道是哪个客户端请求的)。accept()方法就会返回请求这个服务的客户端的Socket实例,然后通过返回的这个Socket实例的方法, 操作传输过来的信息。当Socket对象操作完毕之后,使用close()方法将其关闭。 

 

ServerSocket

/**     * Waits for an incoming request and blocks until the connection is opened.     * This method returns a socket object representing the just opened     * connection.     *     * @return the connection representing socket.     * @throws IOException     *             if an error occurs while accepting a new connection.     */    public Socket accept() throws IOException {        checkClosedAndCreate(false);        if (!isBound()) {            throw new SocketException("Socket is not bound");        }        Socket aSocket = new Socket();        try {            implAccept(aSocket);        } catch (SecurityException e) {            aSocket.close();            throw e;        } catch (IOException e) {            aSocket.close();            throw e;        }        return aSocket;    }

 

    /**     * Closes this server socket and its implementation. Any attempt to connect     * to this socket thereafter will fail.     *     * @throws IOException     *             if an error occurs while closing this socket.     */    public void close() throws IOException {        isClosed = true;        impl.close();    }

Socket一般有两种类型:TCP套接字和UDP套接字。

TCP 和UDP在传输过程中的具体实现方法不同。两者都接收传输协议数据包并将其内容向前传送到应用层。TCP把消息分解成数据包(数据 报,datagrams)并在接收端以正确的顺序把它们重新装配起来,TCP还处理对遗失数据包的重传请求,位于上层的应用层要处理的事情就少多了。 UDP不提供装配和重传请求这些功能,它只是向前传送信息包。位于上层的应用层必须确保消息是完整的,并且是以正确的顺序装配的。

【网络编程】Socket基础