socket一瞥

Socket 简介

Socket( 套接字 ) 是一种抽象层,应用程序通过它来发送和接受数据,与网络中其他应用程序进行通信。下图描述应用程序、套接字抽象层、协议、端口号之间的逻辑关系。



 

 

基本概念

Socket 编程中一些基本概念是必须要了解的。如:网间进程通信、端口、地址、连接、半相关 ( 协议,本地地址,本地端口号 ) 、全相关 ( 协议,本地地址,本地端口号,远地地址,远地端口号 ) 等等。

 

服务方式

         OSI 模型中,各层之间是严格单向依赖,各层次分工和协作集中体现在相互之间的界面上。“服务”是描述其之间关系的抽象概念,即网络中各层向紧邻上层提供的一组操作。在 OSI 的术语中,网络层及其以下各层又称为通信子网,只提供点到点通信,没有程序或进程的概念。而传输层实现的是“端到端”通信,引进网间进程通信概念,同时也要解决差错控制,流量控制,数据排序(报文排序),连接管理等问题,为此提供不同的服务方式:    面向连接(虚电路)或无连接。

面向连接服务是电话系统服务模式的抽象,即每一次完整的数据传输都要经过建立连接,使用连接,终止连接的过程。在数据传输过程中,各数据分组不携带目的地址,而使用连接号 (connect ID) 。本质上,连接是一个管道,收发数据不但顺序一致,而且内容相同。 TCP 协议提供面向连接的虚电路。  

 

无连接服务是邮政系统服务的抽象,每个分组都携带完整的目的地址,各分组在系统中独立传送。无连接服务不能保证分组的先后顺序,不进行分组出错的恢复与重传,不保证传输的可靠性。 UDP 协议提供无连接的数据报服务。

 

C/S 模型:




 

        

TCP/IP Socket 提供下列三种类型套接字:

流式套接字( SOCK_STREAM  

提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复地发送,且按发送顺序接收。内设流量控制,避免数据流超限;数据被看作是字节流,无长度限制。文件传送协议( FTP )即使用流式套接字。  

 

数据报式套接字( SOCK_DGRAM  

提供了一个无连接服务。数据包以独立包形式被发送,不提供无错保证,

数据可能丢失或重复,并且接收顺序混乱。网络文件系统( NFS )使用数据报式套接字。  

 

原始式套接字( SOCK_RAW  

该接口允许对较低层协议,如 IP ICMP 直接访问。常用于检验新的协议实现或访问现有服务中配置的新设备。

 

Java socket API:javasocket 主要用到类有 ServerSocketSocketSocket 构造函数有:

public Socket(String host, int port) throws UnknownHostException, IOException;

public Socket(InetAddress address, int port) throws IOException;

public Socket(String host, int port, InetAddress localAddr,int localPort) throws IOException;

 

Socket  主要 Method:

public synchronized void close() throws IOException

public void connect(SocketAddress endpoint);

public void connect(SocketAddress endpoint, int timeout)

public synchronized void setSoTimeout(int timeout)

 

 

SocketServer 构造函数 :

public ServerSocket(int port) throws IOException;

public ServerSocket(int port, int backlog) throws IOException;

public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException;

SocketServer Method:

public void bind(SocketAddress endpoint) throws IOException;

public void bind(SocketAddress endpoint, int backlog) throws IOException  public Socket accept() throws IOException;

public synchronized void setSoTimeout(int timeout) throwsSocketException;

public void close() throws IOException;

 

 

客户端实现:

Socket  socket =  new  Socket ();

       OutputStream os =  null ;

       DataInputStream is =  null ;

        try  {

           socket.connect( new  InetSocketAddress( bill.****.com , 8215 ), TIME_OUT );

           socket.setSoTimeout( TIME_OUT ); //5000 毫秒等待读设置

           os = socket.getOutputStream();

           DataOutputStream dos =  new  DataOutputStream(os);

           is =  new  DataInputStream(socket.getInputStream());

           dos.writeInt(post.getBytes(). length );

           dos.flush();

           dos.write(post.getBytes());

           dos.flush();

            //  读取 socket 传入字节长度

            int  len = is.readInt();

            byte [] buff =  new   byte [len];

            int  rec = is.read(buff, 0, buff. length );        

            if  (rec == -1 || rec != buff. length ) {

               throw   new  Exception( " ***** " );             }

           String msg =  new  String(buff);

            if  (! "1" .equals(msg)) {

               throw   new  Exception(msg);

           }

            //write log

       }  catch  (Exception e) {

            //write log

            throw   new  RuntimeException( " ***** " );

       }  finally  {

            try  {

               if  (os !=  null )

                  os.close();

               if  (is !=  null )

                  is.close();

               if  (socket !=  null )

                  socket.close();

           }  catch  (Exception e) {

               logger .error(e.toString());

           }

       }

 

服务器端 java 版本:

     public   void  doListen() {

       ServerSocket server;

        try  {

           server =  new  ServerSocket(8215);

            while  ( true ) {

              Socket client = server.accept();

               new  Thread( new  SSocket(client)).start();

           }

       }  catch  (IOException e) {

           e.printStackTrace();

       }

 

    }

 

     // 服务器进程

     class  SSocket  implements  Runnable {

       Socket  client ;

        public  SSocket(Socket client) {

            this . client  = client;

       }

        public   void  run() {

           DataInputStream input;

           DataOutputStream output;

            try  {

              input =  new  DataInputStream( client .getInputStream());

              output =  new  DataOutputStream( client .getOutputStream());

             

              String rev = input.readUTF();

               int  result = dealWith(rev); // 业务处理 ;

              output.writeInt(result);

             

           }  catch  (IOException e) {

              e.printStackTrace();

           }

       }

    }

 

Socket 阻塞问题

Socket  I/O 调用可能会因为多种原因而阻塞。

数据输入方法  read()  receive() 在没有数据可读时会阻塞。

TCP 套接字的  write() 方法在没有足够的空间缓存传输的数据时可能阻塞。

ServerSocket  accept() 方法和  Socket 的构造函数都会阻塞等待,直到连接建立。

长的信息往返时间,高错误率的连接和慢速的(或已发生故障的)服务器,都可能导致需要很长的时间来建立连接。

所有这些情况,只有在连接请求得到满足后这些方法才会返回。当然,调用一个已经阻塞的方法将使应用程序停止(并使运行它的线程无效)。当程序在等待一次调用的完成时如果还有其他任务要执行的情况会怎样(如,更新 " 忙碌 " 状态的光标或响应用户请求)?这些程序可能没有时间来等待一个阻塞的方法调用。那 UDP 数据报文丢失的情况呢?如果我们阻塞等待接收一个数据报文,而它已经丢失,则会导致程序无限期地阻塞下去。

 

Socket 超时处理     

accept(),read() receive() 对于这些方法,我们可以使用  Socket 类、 ServerSocket 类的

setSoTimeout() 方法,设置其阻塞的最长时间(以毫秒为单位)。如果在指定时间内这些方

法没有返回,则将抛出一个  InterruptedIOException ,提示 Read time out 异常。对于  Socket 实例,在调用  read( () 方法,设置其阻塞的最长时间(以毫秒为单位)。还可以使用该套接字的  InputStream  available() 方法来检测是否有可读的数据。

 

连接和写数据

Socket 类的构造函数会尝试根据参数中指定的主机和端口来建立连接,并阻塞等待,直

到连接成功建立或发生了系统定义的超时。不幸的是,系统定义的超时时间很长,而  Java

又没有提供任何缩短它的方法。要改变这种情况,可以使用  Socket 类的无参数构造函数,

它返回的是一个没有建立连接的  Socket 实例。需要建立连接时,调用该实例的  connect() 方法,并指定一个远程终端和超时时间(毫秒)。 write() 方法调用也会阻塞等待,直到最后一个字节成功写入到了  TCP 实现的本地缓存中。如果可用的缓存空间比要写入的数据小,在  write() 方法调用返回前,必须把一些数据成功传输到连接的另一端。因此, write() 方法的阻塞总时间最终还是取决于接收端的应用程序。不幸的是  Java 现在还没有提供任何使  write() 超时或由其他线程将其打断的方法。所以如果一个可以在  Socket 实例上发送大量数据的协议可能会无限期地阻塞下去。

 

限制每个客户端的时间

现在假设要实现一个为每个客户端限定了服务时间的回显协议。也就是说我们定义一个

了目标, TIMELIMIT ,并在协议中实现经过  TIMELIMIT 毫秒后,实例就自动终止。协议实

例保持了对剩余服务时间的跟踪,并使用  setSoTimeout() 方法来保证  read() 方法的阻塞时间

不会超过  TIMELIMIT 。由于没有办法限制  write() 调用的时间,我们并不能保证所定义的时

间限制真正有效。

 

Socket 传输特点:

优点

传输数据为字节级,传输数据可自定义,数据量小 ;

传输数据时间短,性能高

适合于客户端和服务器端之间信息实时交互

可以加密 , 数据安全性强

缺点:

需对传输的数据进行解析,转化成应用级的数据

对开发人员的开发水平要求高

相对于 Http 协议传输,增加了开发量

 

Socket 长短连接

所谓长连接,指在一个 TCP 连接上可以连续发送多个数据包,在 TCP 连接保持期间,如果没有数据包发送,需要双方发检测包以维持此连接,一般需要自己做在线维持。  
    
短连接是指通信双方有数据交互时,就建立一个 TCP 连接,数据发送完成后,则断开此 TCP 连接,一般银行都使用短连接。

猜你喜欢

转载自ericlixj.iteye.com/blog/1755082