• Linux Socket编程注意事项


    Socket API 是网络应用程序开发中实际应用的标准 API。虽然该 API 简单。可是开发新手可能会经历一些常见的问题。本文识别一些最常见的隐患并向您显示怎样避免它们。

    隐患 1.忽略返回状态

    第一个隐患非常明显,但它是开发新手最easy犯的一个错误。

    假设您忽略函数的返回状态,当它们失败或部分成功的时候,您或许会迷失。

    反过来。这可能传播错误。使定位问题的源头变得困难。

    捕获并检查每个返回状态。而不是忽略它们。考虑清单 显示的样例,一个套接字 send 函数。

    清单 1. 忽略 API 函数返回状态

    int status, sock, mode;
    /* Create a new stream (TCP) socket */
    sock = socket( AF_INET, SOCK_STREAM, 0 );
    ...
    status = send( sock, buffer, buflen, MSG_DONTWAIT );
    if (status == -1) {
      /* send failed */
      printf( "send failed: %s
    ", strerror(errno) );
    } else {
      /* send succeeded -- or did it? */
    }


    清单 探究一个函数片断,它完毕套接字 send 操作(通过套接字发送数据)。函数的错误状态被捕获并測试,但这个样例忽略了 send 在无堵塞模式(由 MSG_DONTWAIT 标志启用)下的一个特性。

    send API 函数有三类可能的返回值:

    · 假设数据成功地排到传输队列。则返回 0

    · 假设排队失败。则返回 -1(通过使用 errno 变量能够了解失败的原因)。

    · 假设不是全部的字符都可以在函数调用时排队,则终于的返回值是发送的字符数。

    因为 send  MSG_DONTWAIT 变量的无堵塞性质,函数调用在发送全然部的数据、一些数据或没有发送不论什么数据后返回。在这里忽略返回状态将导致不全然的发送和随后的数据丢失。

     

    隐患 2.对等套接字闭包

    UNIX 有趣的一面是您差点儿能够把不论什么东西看成是一个文件。文件本身、文件夹、管道、设备和套接字都被当作文件。

    这是新颖的抽象,意味着一整套的 API 能够用在广泛的设备类型上。

    考虑 read API 函数,它从文件读取一定数量的字节。

    read 函数返回读取的字节数(最高为您指定的最大值);或者 -1,表示错误;或者 0,假设已经到达文件末尾。

    假设在一个套接字上完毕一个 read 操作并得到一个为 的返回值,这表明远程套接字端的对等层调用了 close API 方法。该指示与文件读取同样 —— 没有多余的数据能够通过描写叙述符读取(參见 清单 2)。

    清单 2.适当处理 read API 函数的返回值

    int sock, status;
    sock = socket( AF_INET, SOCK_STREAM, 0 );
    ...
    status = read( sock, buffer, buflen );
    if (status > 0) {
      /* Data read from the socket */
    } else if (status == -1) {
      /* Error, check errno, take action... */
    } else if (status == 0) {
      /* Peer closed the socket, finish the close */
      close( sock );
      /* Further processing... */
    }


    相同,能够用 write API 函数来探測对等套接字的闭包。

    在这样的情况下,接收 SIGPIPE 信号,或假设该信号堵塞,write 函数将返回 -1 并设置 errno  EPIPE

     

    隐患 3.地址使用错误(EADDRINUSE)

    您能够使用 bind API 函数来绑定一个地址(一个接口和一个port)到一个套接字端点。能够在server设置中使用这个函数,以便限制可能有连接到来的接口。也能够在client设置中使用这个函数,以便限制应当供出去的连接所使用的接口。bind 最常见的使用方法是关联port号和server,并使用通配符地址(INADDR_ANY),它同意不论什么接口为到来的连接所使用。

    bind 普遍遭遇的问题是试图绑定一个已经在使用的port。

    该陷阱是或许没有活动的套接字存在,但仍然禁止绑定port(bind 返回EADDRINUSE)。它由 TCP 套接字状态 TIME_WAIT 引起。该状态在套接字关闭后约保留 到 分钟。

     TIME_WAIT 状态退出之后。套接字被删除,该地址才干被又一次绑定而不出问题。

    等待 TIME_WAIT 结束可能是令人恼火的一件事,特别是假设您正在开发一个套接字server,就须要停止server来做一些修改,然后重新启动。幸运的是,有方法能够避开 TIME_WAIT 状态。能够给套接字应用 SO_REUSEADDR 套接字选项,以便port能够立即重用。

    考虑清单 的样例。在绑定地址之前,我以 SO_REUSEADDR 选项调用 setsockopt

    为了同意地址重用,我设置整型參数(on)为 (不然。能够设为 来禁止地址重用)。

     

     

    清单 3.使用 SO_REUSEADDR 套接字选项避免地址使用错误

    int sock, ret, on;
    struct sockaddr_in servaddr;
    /* Create a new stream (TCP) socket */
    sock = socket( AF_INET, SOCK_STREAM, 0 ):
    /* Enable address reuse */on = 1;
    ret = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );
    /* Allow connections to port 8080 from any available interface */
    memset( &servaddr, 0, sizeof(servaddr) );servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl( INADDR_ANY );
    servaddr.sin_port = htons( 45000 );
    /* Bind to the address (interface/port) */
    ret = bind( sock, (struct sockaddr *)&servaddr, sizeof(servaddr) );


    在应用了 SO_REUSEADDR 选项之后,bind API 函数将同意地址的马上重用。

    隐患 4.TCP 中的帧同步假定

    TCP 不提供帧同步,这使得它对于面向字节流的协议是完美的。这是 TCP 与 UDPUser Datagram Protocol,用户数据报协议)的一个重要差别。UDP 是面向消息的协议,它保留发送者和接收者之间的消息边界。TCP 是一个面向流的协议,它假定正在通信的数据是无结构的,如图 所看到的。

    图 1UDP 的帧同步能力和缺乏帧同步的 TCP

    图 的上部说明一个 UDP client和server。左边的对等层完毕两个套接字的写操作,每一个 100 字节。

    协议栈的 UDP 层追踪写的数量,并确保当右边的接收者通过套接字获取数据时,它以相同数量的字节到达。换句话说。为读者保留了写者提供的消息边界。

    如今,看图 的底部.它为 TCP 层演示了同样粒度的写操作。两个独立的写操作(每一个 100 字节)写入流套接字。

    但在本例中,流套接字的读者得到的是 200 字节。协议栈的 TCP 层聚合了两次写操作。这样的聚合能够发生在 TCP/IP 协议栈的发送者或接收者中不论什么一方。

    重要的是,要注意到聚合或许不会发生 —— TCP 仅仅保证数据的有序发送。

    对大多数开发者来说,该陷阱会引起困惑。

    您想要获得 TCP 的可靠性和 UDP 的帧同步。除非改用其它的传输协议,比方流传输控制协议(STCP),否则就要求应用层开发者来实现缓冲和分段功能。

  • 相关阅读:
    Dubbo监控中心
    Dubbo 提供者配置&测试
    IDEA中pom.xml依赖另一个项目
    MBG
    查询优化技术之多级缓存
    分布式扩展流程
    Redis取值时取出的是HashMap
    linux执行sql
    Git的使用
    405
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/5169708.html
Copyright © 2020-2023  润新知