zoukankan      html  css  js  c++  java
  • 【网络基础编程】第三节 C/S

    学习地址:
    C语言中文网 - 实现迭代服务端和客户端
    GNU - Closing a Socket

    前面介绍的程序,不管Service 端还是 Client端,都有一个问题,就是处理完一个 accept 请求立即退出,没有太大的实际意义。能不能像Web 服务器那样一直接收Client 端的请求呢?能,使用 While 循环即可。

    修改前面的代码,是我们的服务端可以不断响应 Client 端的请求。

    升级版Socket Demo

    1. socket缓冲区

    在迭代服务端和客户端的核心,就是如何使用write() 和 read() 函数,接下来介绍数据是如何传递的。

    write() 函数并不立即向网络中传输 Data,而是先将 Data 写入缓冲区中,再由 TCP 协议将数据从缓冲区发送到目标机器。一旦将 Data 写入缓冲区,函数就可以成功返回,不管 Data 有没有到达目标机器,也不管他们何时被发送到网络,这些都是 TCP 协议负责的事情。

    TCP 协议独立于 write() 函数,Data 有可能刚被写入缓冲区就发送到网络,也可能在缓冲区中不断积压,多次写入的数据被一次性发送到网络,这要取决于网络情况、当前线程是否空闲等诸多因素,不由程序员控制。

    read()函数也是如此,也从输入缓冲区中读取 Data,而不是直接从网络读取。

    这些I/O 缓冲区特性可整理如下:

    • I/O 缓冲区在每个 TCP 套接字中单独存在;
    • I/O 缓冲区在创建套接字时自动生成;
    • 即使关闭套接字也会继续传送输出缓冲区中遗留的 Data;
    • 但是关闭套接字也将丢失输入缓冲区中的 Data。

    输入/输出 缓冲区的默认大小可以通过getsockopt() 函数获取:

        unsigned optVal;
        socklen_t optLen = sizeof(int);
        getsockopt(serv_socket, SOL_SOCKET, SO_SNDBUF, (char*)&optVal, &optLen);
        printf("Buffer length: %d
    ", optVal);
    
        // 结果:2^17
        Buffer length: 131072 
    

    2. 阻塞模式

    对于 TCP 套接字(默认情况下)。

    当使用write() 函数发送数据时:####

    • 首先会检查输出缓冲区,如果缓冲区的可用长度小于要发送的数据,那么write() 会阻塞(暂停执行),直到输出缓冲区中的 Data 被发送到目标机器,腾出足够的空间,才唤醒 write() 函数继续写入 Data。
    • 如果 TCP 协议正在向网络发送 Data,那么输出缓冲区会被锁定,不允许吸入,write() 也会被阻塞(暂停执行),知道数据发送完毕输出缓冲区解锁,才唤醒write() 函数继续写入 Data。
    • 如果要写入的 Data 大于缓冲区的最大长度,那么 Data 将分批写入。
    • 知道所有的数据被写入输出缓冲区, write() 才能返回。

    当使用read() 函数读取数据时:####

    • 首先会检查输入缓冲区,如果缓冲区中有数据,那么就会读取,否则函数会被阻塞,知道网络上数据来到。
    • 如果要读取的数据长度小于缓冲区的数据长度,那么就不能一次性将缓冲区中的数据独处,剩余数据将不断积压,直到read() 函数再次读取。
    • 直到读取完数据之后,read() 函数才会返回,否则一直被阻塞。

    阻塞模式总结

    以上就是TCP 套接字的阻塞模式。所谓阻塞,也就是上一步动作没有完成,下一步动作将被暂停,直到上一步动作完成之后才能继续,以保持同步性。


    3. 使用域名获取IP 地址

    包含: #include<netdb.h>
    

    首先介绍netdb.h 中的网络数据库返回的结构:#####

    struct hostent {
    	char	*h_name;	/* official name of host */
    	char	**h_aliases;	/* alias list */
    	int	h_addrtype;	/* host address type */
    	int	h_length;	/* length of address */
    	char	**h_addr_list;	/* list of addresses from name server */
    #if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
    #define	h_addr	h_addr_list[0]	/* address, for backward compatibility */
    #endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
    };
    
    • h_name :官方域名。
    • h_aliases :别名,多个域名访问同一个主机。同一个IP地址可以绑定多个域名,因此除了当前域名还可以指定其他域名。
    • h_addrtype :gethostbyname() 不仅仅支持IPv4,还可以支持IPv6,可以通过此成员获取IP 地址族信息。
    • h_lenght :保存IP 地址的长度,IPv4长度为4 个字节,IPv6长度为16 个字节。
    • h_addr_list :重要成员。通过该成员以整数形式保存域名对应的IP 地址。对于用户较多的服务器,可能会分配多个IP 地址给同一个域名,利用多个服务器进行均衡负载。

    struct hostent 结构体变量的组成如下图所示:####

    测试代码:####

    假设获取本机的IP 地址。步骤:1.通过gethostname()获取本机的域名;2.通过gethostbyname() 获取域名的IP 数据库信息。

    (因为在iOS8.0以上真机测试,通过gethostbyname() 无法解析域名来获取IP 信息了,推荐使用getifaddrst来获取IP地址)###

        struct hostent * struct_hLib; // 储存IP信息的结构体
        char ** p_h_addr_list;        // 获取IP信息中IP列表
        char str[32];                 // 获取IP列表中具体的IP地址
        char hostname[32];            // 储存域名
        
        gethostname(hostname, sizeof(hostname));      // 获取本地域名,存储到hostname
        struct_hLib = gethostbyname(hostname);        // 获取指定域名的IP信息,存储到struct_hLib
        p_h_addr_list = struct_hLib->h_addr_list;     // 通过struck_hLib 获取IP列表
        
        for (; *p_h_addr_list!=NULL; p_h_addr_list++)
        {
            //*> 打印具体的IP地址
            printf("address: %s
    ",inet_ntop(struct_hLib->h_addrtype, *p_h_addr_list, str, sizeof(str)));
        }
    

    打印结果:

    address: 192.168.1.3
    

    讲解一下inet_ntopgethostnamegethostbyname的用法:

    1.inet_ntop:####

    const char * inet_ntop(int af, const void *restrict src, char *restrict dst, socklen_t size);

    官方文档解释:

         The function inet_ntop() converts an address *src from network format
         (usually a struct in_addr or some other binary form, in network byte
         order) to presentation format (suitable for external display purposes).
         The size argument specifies the size, in bytes, of the buffer *dst.  It
         returns NULL if a system error occurs (in which case, errno will have
         been set), or it returns a pointer to the destination string.  This func-tion function
         tion is presently valid for AF_INET and AF_INET6.
    
    • af : Address Family。
    • src : 来自于网络地址格式,例如*p_h_addr_list 这种二进制形式的地址。
    • dst :存放转化后的字符串指针。
    • size : 返回字节的大小。

    返回把网络地址转换成本地地址。

    2.gethostname####

    int gethostname(char * destinnationStr, size_t);

    • destinnationStr :存放本地域名的字符串指针。
    • size_t : 存放本地地址的长度。

    返回当前本地域名

    3.gethostbyname

    struct hostent *gethostbyname(const char *);

  • 相关阅读:
    CSS3 之 RGBa 可透明颜色
    编写高效的CSS选择器
    CSS3中轻松实现渐变效果
    Sublime Text:学习资源篇
    [1]移动端页面调试之“weinre大法”
    解决win10 phptoshop #fff纯白不是这样的白 显示器高级的问题
    Jquery过滤选择器,选择前几个元素,后几个元素,内容过滤选择器等
    如何理解Box-sizing模型?
    使用CSS3制作酷炫防苹果复选框 自行测试!
    mysql 将时间戳直接转换成日期时间
  • 原文地址:https://www.cnblogs.com/R0SS/p/5517729.html
Copyright © 2011-2022 走看看