客户端Socket概述与实例

来源:互联网 发布:淘宝买全民晒单 编辑:程序博客网 时间:2024/05/17 00:09

绝大部分知识与实例来自O’REILLY的《Java网络编程》(Java Network Programming,Fourth Edition,by Elliotte Rusty Harold(O’REILLY))。

Socket类简介

Socket又名套接字,由地址和端口号组成。它可以完成以下7个基本操作:
(1)连接远程机器;
(2)发送数据;
(3)接收数据;
(4)关闭连接;
(5)绑定端口;
(6)监听入站数据;
(7)在绑定端口上接收来自远程机器的连接。
Java的Socket类提供了对应前4个操作的方法,后面3个方法用于等待客户端的连接,仅服务器需要,由ServerSocket实现。
Socket类的使用大致可分为两个基本步骤:构造一个Socket对象并完成配置;利用Socket对象连接远程主机,并获取输入/输出流。

Socket对象的构建与简单使用

Socket的构造函数如下:

//构建一个空的Socket对象public Socket()//构建一个空的Socket对象,并设置代理服务器public Socket(Proxy proxy)//构建一个空的Socket对象,并设置加密机制public Socket(SocketImpl impl)//根据主机名和端口号构造Socket对象public Socket(String host, int port) throws UnknownHostException, IOException//根据InetAddress对象和端口号构造Socket对象public Socket(InetAddress address, int port) throws IOException//允许设置在哪个本地接口连接public Socket(String host, int port, InetAddress localAddr,int localPort) throws IOException

各个构造器的参数见注释。需要注意的是,前三个构造器在创建对象时不会打开与远程主机的连接(因为没有提供地址和端口号),而后面的构造器则会。另外,由于Socket实现了Closeable,因此最好利用Java 7的try-with-resources实现自动关闭。
创建Socket对象并建立连接后,就可以调用Socket的getInputStream()获取来自服务器的输入了。

实例1:Daytime协议客户端

public static void showDayTime(){    String hostName = "time.nist.gov";    try(Socket socket = new Socket(hostName, 13)){        socket.setSoTimeout(15 * 1000);        StringBuilder builder = new StringBuilder();        try(InputStreamReader reader =                 new InputStreamReader(socket.getInputStream(),"ASCII")){            for(int c = reader.read() ; c != -1 ;c = reader.read()){                builder.append((char)c);            }        }        System.out.println(builder.toString());    } catch (UnknownHostException e) {        System.out.println("Unknown Host.");    } catch (IOException e) {        e.printStackTrace();    }}public static void main(String[] args){    showDayTime();}输出:58007 17-09-11 02:33:20 50 0 0 938.2 UTC(NIST) * 

向服务器写入数据

如果需要向服务器写入数据,只需要通过Socket的getOutputStream()方法获得一个输出流,然后向这个输出流输出数据即可。输出结束后必须手动调用输出流的flush()方法确保发送。

关闭Socket

close()方法同时关闭输入和输出,如果只想关闭一半,可以使用shutdownInput()和shutdownOutput()方法。

获取Socket对象的信息

Socket类提供了一些方法,用于获取某个Socket对象的信息:

//获取远程主机地址public InetAddress getInetAddress()//获取远程主机端口public int getPort()//获取本地端口public int getLocalPort()//连接是否处于关闭状态public boolean isClosed()//连接是否成功打开过public boolean isConnected()//Socket是否成功绑定到本地系统的出站端口public boolean isBound()public String toString()输出样例:Socket[addr=www.baidu.com/183.232.231.172,port=80,localport=10307]

设置Socket选项

Socket选项指定了Java Socket依赖的原生socket如何发送和接收数据。有以下选项可用:
(1)TCP_NODELAY

public void setTcpNoDelay(boolean on) throws SocketExceptionpublic boolean getTcpNoDelay() throws SocketException

正常状况下,为了提升效率,小数据包发送前会组合成大包再发送。设置TCP_NODELAY为true可确保包会尽可能快地发送,无论包的大小。简单来讲,setTcpNoDelay(true)会关闭socket的缓冲功能。

(2)SO_LINGER

public void setSoLinger(boolean on, int linger) throws SocketExceptionpublic int getSoLinger() throws SocketException

SO_LINGER指定了Socket关闭时如何处理尚未发送的数据报。默认情况下,close()方法会立即返回,但系统仍会尝试发送剩余的数据。如果延迟时间设置为0,那么当Socket关闭时,所有未发送的数据报都将被丢弃。如果SO_LINGER设置为打开并设置一个任意正数的延迟时间,close()方法会阻塞,等待发送数据和接收确认。
当这个选项被禁用时,getSoLinger()方法返回-1。

(3)SO_TIMEOUT

public synchronized void setSoTimeout(int timeout) throws SocketExceptionpublic synchronized int getSoTimeout() throws SocketException

正常情况下,尝试从Socket读取数据时,read()方法会阻塞尽可能长的时间来得到足够的字节。设置SO_TIMEOUT可以确保一次调用阻塞的时间不超过某个固定的毫秒数。如果超时,会抛出一个InterruptedIOException,但不会中断socket的连接。

(4)SO_RCVBUF与SO_SNDBUF

public synchronized void setReceiveBufferSize(int size) throws SocketExceptionpublic synchronized int getReceiveBufferSize() throws SocketExceptionpublic synchronized void setSendBufferSize(int size) throws SocketExceptionpublic synchronized int getSendBufferSize() throws SocketException

用于设置接收缓冲区大小与发送缓冲区大小,单位为字节。一般来说,如果不能充分利用带宽,应当增大缓冲区;若网络拥塞严重,应当减小缓冲区。

(5)SO_KEEPALIVE

public void setKeepAlive(boolean on) throws SocketExceptionpublic boolean getKeepAlive() throws SocketException

如果打开了SO_KEEPALIVE,客户端会偶尔通过一个空闲连接发送一个数据包,以确保服务器未崩溃。如果服务器未能响应,客户端会继续尝试一段时间(一般12分钟),直到接收到响应为止,否则连接将被关闭。

(6)SO_REUSEADDR

public void setReuseAddress(boolean on) throws SocketExceptionpublic boolean getReuseAddress() throws SocketException

设置是否允许多个Socket绑定到同一个端口,默认为false(不允许)。这个设置想要生效,首先它要在绑定端口之前调用,也就是要先用非连接的几种构造器创建Socket对象,然后设置该属性为true,最后再调用connect()完成连接。还有一点,新老Socket必须同时设置该属性为true,否则该设置也无法起效。

以上几个属性的setter如果抛出SocketException,一般指底层socket不支持该属性。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 在饿了么点外卖吃出虫子怎么办 1岁半宝宝拉肚子拉水怎么办 五个多月宝宝拉鼻涕便怎么办 一岁宝宝拉鼻涕样大便怎么办 宝宝拉粘液大便鼻涕状的怎么办 十个月宝宝拉鼻涕一样大便怎么办 7个月宝宝咳嗽反反复复发热怎么办 婴儿3个月突然不吃奶瓶怎么办? 2个月婴儿突然不肯用奶瓶怎么办 喝母乳的宝宝不喝奶瓶怎么办 三个月宝宝不喝奶瓶母乳不够怎么办 七个多月的宝宝不吃辅食怎么办 婴儿光认奶粉不认母乳怎么办 宝宝11个月断奶不吃奶瓶怎么办 4个月的宝宝断奶不肯吃奶瓶怎么办 晚上磨牙齿把牙神经磨坏怎么办 喝母乳的宝宝不喝奶粉怎么办 我宝宝的牙齿长的不整齐怎么办? 宝宝5个月了母乳不够吃怎么办 4个月宝宝母乳不够吃怎么办 11个月宝宝只吃母乳怎么办 10个月宝宝突然不吃母乳怎么办 2个月宝宝咳嗽怎么办是吃母乳的 九个月宝宝不喜欢吃粥和米糊怎么办 9个月宝宝突然不吃辅食怎么办 宝贝8个月不吃辅食怎么办 11个月宝贝不吃辅食怎么办 十一个月宝宝长牙不吃辅食怎么办 八个多月的宝宝不爱吃辅食怎么办 7个月的宝宝不爱吃辅食怎么办 宝宝只吃母乳不吃辅食怎么办 10个月的宝宝不肯吃勺子怎么办 十一个月大宝宝不吃奶吃饭怎么办 十一个月宝宝光吃奶不吃饭怎么办 20个月宝宝爱吃奶不爱吃饭怎么办 宝宝8个多月不肯米糊跟粥怎么办 8个月宝宝突然不肯吃米糊了怎么办 八个月宝宝突然不吃辅食怎么办 八个月宝宝拉屎费劲还干怎么办 两个月的小孩不喜欢吃奶粉怎么办 三个多月的宝宝不爱吃奶怎么办