网络通信之Socket小结

最近在写一个关于数据通信系列的文章,所以Socket是少不了的,今天就和大家来简单分享下Socket的使用方式,以及关于Socket的几个比较重要,容易被小伙伴们忽略且常用的方法,
好了,进入今天的正题。
之前有在面试时候问到http请求底层是基于什么实现的,没错http请求底层也是基于socket的。 另外Socket也就是我们通常说的TCP的封装形式。

说起TCP大家都知道“三次握手”这个协议。我们的客户端Socket和服务端ServerSocket建立了联系之后,双方都确定了对方的身份,证明大家都是认识的是朋友,才可以进行“悄悄话的交流”。下面我们来分析Socket与服务端ServerSocket建立联系的三次握手过程:

(1)第一次握手:建立连接时,客户端Socket向服务端ServerSocket发送SYN包,并进入SYN_SEND状态,等待服务器B确认。这个过程,就好比我向你打电话,我的手机号通过信号到了你的手机上并显示 156XXXXXXXX来电,此时要等你确认这个手机号。

(2)第二次握手:此时服务端收到客户端的SYN包,与客户端的SYN进行确认,确认后,服务端向客户端发送个SYN包,即SYN+ACK 包。服务端进入SYN_RECV状态。这个过程就好比,当收到某人的来电后,我确认手机号是我的朋友,此时我要接通他的电话。

(3)第三次握手:客户端收到服务端发送过来的SYN + ACK包,此时客户端像服务端再发送一个ACK确认包。此时发送完毕后,客户端与服务端就进入了ESTABLISHED状态,完成通信前的三次握手。这个过程就好比,当我接通了电话后,我问对方是XXX吗?对方说是的!(妈的,终于可以交流了。。。)

接下来看看Sokcet的简单使用。

(1)创建客户端Socket:

try {
            Socket socket = new Socket("192.168.191.1", 8888);
            socket.setSoTimeout(3000);
            socket.setKeepAlive(true);
            socket.setTcpNoDelay(true);
            socket.setSoLinger(true, 5);
            socket.setReceiveBufferSize(1024);
            socket.setReuseAddress(true);

            OutputStream oup = socket.getOutputStream();
            oup.write("nihao I'm client".getBytes());

            byte[] readbyte = new byte[40];
            InputStream ins = socket.getInputStream();
            ins.read(readbyte);
            System.out.println(new String(readbyte));

        } catch(SocketException e){
            e.printStackTrace();
        }catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

在上述代码中我们可以看到,需要得到一个socket的实例,然后对其进行相关参数设置,通过socket得到InputStream或者OutputStream 。以上的七个参数的作用分别为:
(1)setSoTimeOut:设置客户端Socket读取数据的超时时长。即当与服务端建立联系后,此时要接收服务端返回的数据,设置该方法可以限定客户端等待服务端发送数据的时间,如果超过了该时长,系统会抛出一个InterruptedIOException异常。在抛出异常后,输入流并未关闭,你可以继续通过read方法读取数据。 如果将timeout设为0,就意味着read将会无限等待下去,直到服务端程序关闭这个Socket.这也是timeout的默认值。

(2)setKeepAlive:该方法指定检测与服务器的链接状态。如果设置参数为true,即打开该设置,此时,客户端会利用空闲的连接每隔两个小时向服务端发送一次数据包进行连接验证服务器是否仍处于活动状态。如果此时服务端未响应,客户端会在第11分钟后继续发送一个验证包,如果在12分钟内服务端还未响应,此时客户端就会执行关闭连接的操作。如果将该设置项关闭,客户端Socket在服务器无效的情况下可能会长时间不会关闭,占据资源。默认情况下是关闭的。

(3)setTcpNoDelay:该方法很有聪明,如果开启该设置,当客户端发送数据给服务端时,发送的过程中,会检测该数据的大小,如果该数据较小,此时不会发送给服务端,而是将较小的包和较大的数据包合,然后一起发送给服务端。在发送下一个数据包时,系统会等待服务器对前一个数据包的响应,当收到服务器的响应后,再发送下一个数据包,这就是所谓的Nagle算法;优点很明显,节省了通信的开销,有效地改善网络传输的效率。在默认情况下是开启的。

(4)setSoLinger:其实该方法和Socket的关闭方法( close() )是有联系的。该方法有两个参数,第一个如果设置为true,即开启该设置。第二个参数指定一个时间值(秒:0 ~ 65535,不可为负值)。该方法的作用是当你调用了Socket的close方法时,系统会去检测是否还有未发送完毕的数据,此时如果存在未发送完毕的数据,系统就会在我们指定的时间内 “努力”发送这些数据到服务器,如果在我们指定的时间内还未发送完毕,那么此时Socket将会执行关闭。如果底层的Socket实现不支持SO_LINGER都会抛出SocketException,可以通过getSoLinger方法来获取延迟关闭的时间,如果返回 -1,则表明SO_LINGER是关闭的。

(5)setReceiveBufferSize:该方法比较简单,设置输入流的缓冲大小。默认情况下,输入流的接收缓冲区是8096个字节(8K)。这个值是Java所建议的输入缓冲区的大小。缓冲值尽量不要设置的太小,否则会导致传输数据过于频繁,从而降低网络传输的效率。如果底层不支持,系统将会抛出IllegalArgumentException异常。

(6)setSendBufferSize:此方法和上面的对称,设置输出流的缓冲大小。其他特点和上面相同,不再赘述。

(7)setReuseAddress:如果你的服务程序停止后想立即重启,不等60秒,而新套接字依旧 使用同一端口,此时 SO_REUSEADDR 选项非常有用。

一般情况下,几个设置项我们都选择开启状态,某些情况下,还需要具体情况具体分析。

接下来看服务端的创建:

ServerSocket ssSocket=null;
        Socket socket=null;
        try {
            //1.注册ip和端口,注册了一个服务器程序
            ssSocket=new ServerSocket(8888);
            //2.等待接收连接请求,并且连接成功后创建Socket
            socket=ssSocket.accept();
            System.out.println("connect ok");
            //3.获得连接对象的网络流,从而进行网络数据传输
            //获得客户端数据
            byte []readbyte=new byte[40];
            InputStream ins=socket.getInputStream();
            //DataInputStream datainput=new DataInputStream(ins);
            //String line=datainput.readUTF();
            ins.read(readbyte);
            System.out.println(new String(readbyte));

            //往客户端发数据
            OutputStream oup=socket.getOutputStream();
            oup.write("nihao I'm server".getBytes());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

这是一个简单的阻塞状态socket通信案例,服务端直到接收到客户端发送的数据才会继续向下执行,接收到客户端的Socket,继续执行流的读写操作来读取和写回数据。关于sockect的更多用法可以参照这篇《基于Socket的Android与PC简单聊天应用的实现》
好了,关于Socket的通信我们就简单分析到这里。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值