android学习笔记——Socket简单介绍

来源:互联网 发布:木马专杀软件 编辑:程序博客网 时间:2024/05/13 06:21
Socket客户端

客户端连接服务器  分为两种方式
  1. 通过IP的方式连接服务器
  2. 通过域名方式连接服务器,但本质是一样的,域名方式要经过DNS(域名解析)解析成IP,然后在连接
Socket类连接服务器最常用的方法就是通过Socket类的构造函数将IP或域名以及端口号作为参数传入Socket对象中。
这里,我们只讨论最简单的构造函数的重载
     public Socket (String host , int port ) host 是IP port 是端口号

除了上述方式外,还可以用Socket.connect 来指定IP和端口(由此可以扫描服务器开着的端口)
     public void connect(SocketAddress remoteAddr , int timeout)throw IOException

下面看一个例子
     SocketAddress socketAddress = new InetSocketAddress(“192.168,17.81”,80);
     Socket socket = new Socket();
     socket.connect(socketAddress,50);

Socket服务端

ServerSocket 对象用于将服务端的IP地址和端口绑定,从而客户端可以通过同一网段的IP地址和端口访问服务端程序。
因此,ServerSocket也叫服务端Socket,主要用于实现服务器程序。

我们来实现一个简单的ServerSocket
     class ServerSocketThread extends Thread{
          @Override
           public void run(){
               try{
                    ServerSocket serverSocket= newServerSocket();
                    serverSocket.bind(new InetSocketAddress(“192.168.56.3”,80));
                    while(true){
                         Socket socket= serverSocket.accept();//accept方法用于接收客户端发来的请求,若无请求会处于阻塞状态
                         socket.getOutputStream().write(“Hello”);//向客户端输出一条信息
                         socket.getOutputStream().flush();//刷新缓冲区一下才能发送出去
                         socket.close();
                    }
               }catch(Exception e){}
          }    
     }

当然,服务器端也可以收数据
     InputStream is = socket.getInputStream();
     InputStreamReader isr = new InputStreamReader(is);
     BufferedReader br = new BufferedReader(isr);
     String a = br.readLine();

关于Socket的发送和接收数据
     Socket.getInputStream 和 Socket.getOutputStream 方法分别用来得到用于读取和写入数据的InputStream 和 OutputStream 对象。在编写实际的网络客户端程序时,是使用getInputStream 还是使用getOutputStream,以及先使用谁应根据具体的情况决定。

关于设置Socket选项

     Socket选项可以指定Socket发送和接收数据的方式,比较常用的有如下8个选项,这8个选项都定义在java.net.SocketOptions接口中,代码如下:
  • public final static int TCP_NODELAY = 0x0001;
  • public final static int SO_REUSEADDR= 0x04;
  • public final static int SO_LINGER= 0x0080;
  • public final static int SO_TIMEOUT= 0x1006;
  • public final static int SO_SNDBUF= 0x1001;
  • public final static int SO_RCVBUF= 0x1002;
  • public final static int SO_KEEPALIVE= 0x0008;
  • public final static int SO_OOBINLINE= 0x1003;

来说一下这8个选项

 TCP_NODELAY

     在默认情况下,客户端向服务器发送数据时,会根据数据包的大小决定是否立即发送。当数据包中的数据很少时,如只有1字节,而数据包的头却又几十个字节,系统会在发送之前先将较小的包合并到较大的包后,一起将数据发送出去。在发送下一个数据包时,系统会等待服务器对前一个数据包的响应,当收到服务器的响应后,再发送下一个数据包,这就是所谓的Nagle算法。在默认情况下,Nagle算法是开启的。
     这种算法虽然可以有效的改善网络传输的效率,但对于网络速度比较慢,而且对实时性的要求比较高的情况下,使用这种方式传输数据会使客户端有明显的停顿现象。因此,最好的解决方案是需要Nagle算法时就使用它,不需要时就关闭它,而使用setTcpTpDelay方法正好可以满足这个需求。当使用setTcpNoDelay(true)将Nagle算法关闭后,客户端每发送一次数据,无论数据包的大小都会将这些数据发送出去。

 SO_REUSEADDR

     通过这个选项,可以使多个Socket对象绑定在同一端口上,这种处理机制对于随机绑定端口的Socket对象没什么影响,但对于绑定固定端口的Socket对象就可能会抛出“Address already in use : JVM_Bind”异常。因此,使用这个选项可以避免抛出这个异常。
     使用SO_REUSRADDR选项是应注意以下几点:
  • 必须在调用bind方法之前使用setReuseAddress方法来打开SO_REUSEADDR选项,因此要想使用SO_REUSEADDR选项,就不能通过socket类的构造方法来绑定端口
  • 必须将绑定同一端口的所有的Socket对象的SOREUSEADDR选项都打开才能起作用。

 SO_LINGER

     这个Socket选项可以影响close方法的行为。在默认情况下,当调用close方法后,将立即返回:如果这是仍然有未被送出的数据包,那么这些数据包将被丢弃。如果将linger参数设为一个正整数n时(n的值最大是65535),在调用close方法后,将最多被阻塞n秒。在这n秒内,系统会尽量将未送出的数据包发送出去;如果超过了n秒,还有未发送的数据包,这些数据包将全部被丢弃;而close方法会立即返回。如果将linger设为0,和关闭SO_LINGER选项的作用是一样的。
     如果底层的Socket实现不支持SO_LINGER就会抛出SocketException异常,当个linger参数传递负数时,setSoLinger还会抛出一个IllegalArgumentException异常。可以通过getSoLinger方法得到延迟关闭的时间,如果返回-1,则表明SO_LINGER是关闭的。

 SO_TIMEOUT

     可以通过这个选项来设置读取数据超时。当输入流的read方法被阻塞时,如果设置timeout,那么系统在等待了timeout毫秒后会抛出一个InterruptedIOException异常。
     如果将timeout设置为0,就意味着read将会无限等待下去,知道服务器程序关闭这个Socket,这也是timeout的默认值。不可以将timeout设置成负数。

 SO_SNDBUF

     在默认情况下,输出流的发送缓冲区是8096字节(8KB),这个值时Java建议的输出缓冲区的大小。如果这个默认值不能满足要求,可以用setSendBufferSize方法来重新设置缓冲区的大小。但最好不要讲输出缓冲区设的太小,否则会导致传输数据过于频繁,从而降低网络传输的效率。

 SO_RCVBUF

     这个选项与SO_SNDBUF类似,它是用来设置接收缓冲区大小的,默认8KB

 SO_KEEPALIVE

     如果将这个Socket选项打开,客户端Socket每隔一段时间(大约两小时)就会利用空闲的连接向服务器发送一个数据包。这个数据包并没有其他的作用,只是为了检测一下服务器是否仍处于活动状态。如果服务器未响应这个数据包,在一段时间后,客户端Socket在发送一个数据包。如果在一段时间内,服务器还没响应,那么客户端Socket将关闭。如果将这个Socket选项关闭,客户端Socket在服务器无效的情况下可能会长时间不会关闭。SO_KEEPALIVE选项在默认情况下是关闭的。

 SO_OOBINLINE

     这个Socket选项打开,可以通过Socket.sendUrgentData方法向服务器发送一个单字节的数据,这个单字节的数据并不经过输出缓冲区,而是立即发出。虽然在客户端并没有使用OutputStream向服务器发送数据,但在服务器端程序中这个单字节的数据是和其他的普通数据混在一起的。因此,在服务器端程序中并不知道有客户端发送过来的数据是由OutputStream还是sendUrgentData发过来的。
     public void sendUrgentData(int Data)throws IOException
     虽然sendUrgentData的data参数是int类型,但只有这个int类型的低字节被发送,其他的三个字节被忽略。

注:在使用OOBInline方法打开SO_OOBINLINE选项时,必须在客户端和服务端程序同时使用setOOBInline方法打开这个选项,否则无法正常用sendUrgentData来发送数据。
0 0
原创粉丝点击