现代TCP/IP网络编程-UDP

UDP 的 connect()

  • 前方提到,如果使用的是 UDP 套接字进行通信的话,可以采取 connect 来进行优化,但是却不知原因。
  • 首先 UDP 的别称叫做 不可靠连接, 也就是说它可以不需要对发送出去的数据负责任,在默认情况下这是对的,因为“效率”。
  • 但是如果一个 UDP 套接字端 需要与另一个端进行多于一次的通信的时候,就会出现性能问题:
    • 具体是: 连接两端通信 -> 发送数据 -> 断开连接 -> 连接两端通信 -> 发送数据 -> 断开连接 ......
    • 可以看出,需要重复的进行 连接和断开, 且这两个操作都是涉及 内核 操作,耗费的资源不可忽略
    • 所以在必要时对 UDP 套接字调用 connect,是有必要的(并不硬性要求两端同时都要调用 connect)
    • 需要注意的是 TCP套接字 同样需要调用(必须调用) connect,虽然调用的函数接口一样,但是意义却是不相同的,前者是为了三次握手建立连接,而 UDP却只是为了能够省去 不必要的断开连接 以及接收到 ICMP错误报文
  • ICMP错误报文,指的是如果对端没办法接收到本端发送的信息的话,会返回一个错误,这个错误使用的就是ICMP(ICMPv4和ICMPv6两种)
    • 如果 UDP 套接字通信时采用的是 未连接(unconnected) 的形式,那么在调用 sendto 接口之后,不管对端有没有收到信息,都会立即返回成功的信息,而即使对端没办法收到信息,且向本端发送了 ICMP 报文,我们也是无法检测到的。
    • 但是如果 UDP 套接字通信时采用的是 连接(connected) 的形式,那么就会接收到一个 EHOSTUNREACH 的错误,我们就能够捕捉到(这点与TCP的处理方式一样)。
  • 假设我们想要断开连接 或者 重新选择一个对端进行通信,也是可以的
    • 所需要做的也仅仅是在此调用一下 connect 接口函数
      struct sockaddr_storage unconnect;
      memset(&unconnect, 0, sizeof unconnect);
      unconnect.ss_family = AF_UNSPEC; /* 将 xxx_family 位置为 AF_UNSPEC 就表明要断开连接 */
      connect(udp_sock, (struct sockaddr *)&unconnect, sizeof unconnect); /* 断开连接 */
      

注: 断开连接或者重新对套接字建连接是 UDP 才可以使用的,千万不要用在 TCP套接字上面!

不要疑惑,每次发送的时候只指定了对端的 IP 和 端口,那我们自己的 IP 和端口呢?这个是由内核为我们完成,自动化就是这么方便

  • TCP 这种面向连接的方式不同, UDP 不管是否是连接的(connected),它依旧是一种不可靠的传输方式,所以当它调用 connect 时,即使对端没有运行,这个函数也不会有任何错误,知道发送第一条信息时才能知道对端到底可不可达。

    Read More

现代TCP/IP网络编程-启航

概念

  • 最具误导性的当属于 TCP/IP 协议了
    • 所谓 TCP/IP 协议指的并不是一个协议,往往在生活中听见的术语如:IP地址TCP连接 等,总会被误导,以为就是一个东西
    • 实际上它们都是彼此独立的 协议 ,只不过会相互合作罢了
    • TCP/IP说的是一个 协议族 ,也就是说是一堆协议的统称
  • 对比 OSITCP/IP 参考模型:
OSI TCP/IP
应用层 表示层 会话层 应用层
传输层 传输层
网络层 网络层
链路层 物理层 网络接口层
  • 其中最常接触的
    • 位于 网络层IP 协议,大家所熟知的 IP地址 就是由它进行封装并传往下一层
    • 位于 传输层TCP/UDP 两个协议, 一个是面向连接(STREAM), 一个是面向数据(DGRAM)的,实际上还有一个但这里不记录。
    • 查看自身 网络信息的办法
      • *nix: 在 Terminal 中输入 ifconfig -a
      • Windows: 在 PowerShell 中输入 ipconfig

        Read More

Linux记录

  • 因为国内的原因,没有办法直接使用官方的源,速度有时候会过慢,在高校内部的人可以回比外边更好一些
  • 而经常出现是根据网上搜索(百度),出来的结果,大都是直接换源,导致很多错误例如 Some Index fail to ... 之类的错误,这是由于每个版本的 Linux 的源都有细微的差别。以最有名的基于 DebianUbuntu 为例子
  • 例如Ubuntu 14.04 的163源应该是:

    deb http://mirrors.163.com/ubuntu/ trusty main restricted universe multiverse
    deb http://mirrors.163.com/ubuntu/ trusty-security main restricted universe multiverse
    deb http://mirrors.163.com/ubuntu/ trusty-updates main restricted universe multiverse
    deb http://mirrors.163.com/ubuntu/ trusty-proposed main restricted universe multiverse
    deb http://mirrors.163.com/ubuntu/ trusty-backports main restricted universe multiverse
    deb-src http://mirrors.163.com/ubuntu/ trusty main restricted universe multiverse
    deb-src http://mirrors.163.com/ubuntu/ trusty-security main restricted universe multiverse
    deb-src http://mirrors.163.com/ubuntu/ trusty-updates main restricted universe multiverse
    deb-src http://mirrors.163.com/ubuntu/ trusty-proposed main restricted universe multiverse
    deb-src http://mirrors.163.com/ubuntu/ trusty-backports main restricted universe multiverse
    
  • Ubuntu 15.04 的163源应该是:

    Read More

Practical cpp

try-throw-catch 三段式

这是异常抛出的方式,简单的用法便是在外部使用的try-catch形式:

//Code-1
int main()
{
    int get_num;
    std::cin >> get_num;
    try
    {
        if(get_num < 0)
            throw get_num
        //Something happen
    }
    catch(int e) //此处括号内的参数的类型和抛出的类型需要一致
    {
        std::cout << "The number " << get_num << " is negative"
                  <std::endl;
    }
    //...
}
  • 这是最简单的使用,在三段式中,try充当的是正常代码块,而catch则是对于抛出异常的处理。catch 可以不止一个,但一定要合理,实际来说,三段式能少用尽量少用,我们一般是这么使用三段式的:

    Read More

Cpp记录10.1k

更新于 2015/7/14 21:14:21

再记录 operator= 重载

  • 因为在类的设计中 重载 = 可能是在所难免的,如果你的类设计比较复杂。
  • 之所以需要重载它是为了当类中包含了复杂的关系的时候,提供了一个人为的保证,最典型的莫过于对象的拷贝:
    1. 假设 类中有一个成员是指针,指向一个对象,这个对象可以是数组,也可以是其他类或者容器。
    2. 当我们执行赋值操作符的时候,假定这里规范的使用赋值运算符,让其一定能调用赋值拷贝构造函数 = ,此时对于这个指针成员,就有两种情形: 拷贝指针 或者 拷贝对象
  • 拷贝指针,即便不重载运算符 = 编译器也会帮你自动实现,这在国内大概就叫做 浅拷贝 ,如果仅仅拷贝指针,这就引发了一个问题,多个对象共享一个实际内存,当执行析构函数的时候,会造成多次析构同一个内存块。
  • 拷贝对象,这是普遍的解决方法,在拷贝的同时,将指针所指向的对象同样做一份拷贝,似乎也不错,但是如果对象太大,似乎并不是什么很喜人的事 情,但也不失为一种好的解决方案

    Read More