zoukankan      html  css  js  c++  java
  • 服务端socket重用属性设置

    初始化socket

    socket是一种系统资源,并不是每次初始化都一定成功,因此为了避免初始化失败,一般使用多次初始化的方式,如下所示:

    unsigned int times = 0x0;
    while((server = socket(PF_INET6, SOCK_STREAM, 0)) < 0 && times < 0x3)
    {       
        times++;
        printf("create socket faild %d times
    ", times);
    }

    设置socket的可重用属性

    一般来说,一个端口释放后需要等待两分钟左右才能被再次使用,SO_REUSEADDR是让端口释放后立即就可以被再次使用。例如:一个进程监听一个端口,进程在某个时候异常重启了,如果socket没有设置可重用属性,那么进程重启后就会出现bind错误,因为同一个端口两次监听的时间间隔需要75秒;如果设置了可重用属性,那么同一个端口释放之后马上就可以再次使用,如下所示:

    int reuse = 0x0;
    result = setsockopt(server, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(int));
    if(result != 0)
    {
        printf(" Fail to set socket reuseraddr options, errno = 0x%x!
    ", result);
    }

    设置socket的保活属性

    TCP是一种面向连接的协议,因此需要实时检查连接是否正常,特别是在上层长时间无数据传输时。一般检查连接是否正常的方式是提供一个保活机制,即定时的发送一种探测报文,可以是上层自己发送,也可以使用socket自己提供的保活机制,也就是保活属性,但是socket自己提供的保活机制一般不可靠,或者说是不完全可靠,因此在实际编程中是两种同时使用。首先上层启用一个任务,定时发送检测报文,然后设置socket的保活属性,以期达到完全可靠,如下所示:

    int optval = 0x1;
    result = setsockopt(server, SOL_SOCKET, SO_KEEPALIVE, (char*)&optval, sizeof(int));
    if(result != 0)
    {
        printf("Fail to set socket keepalive options, errno = 0x%x!
    ", result);
    }

    设置socket的缓冲区大小属性

    调用send和recv接口操作数据时,是直接将数据拷贝到缓冲区或是从缓冲器拷贝数据,如果缓存区满了,溢出后就会丢失数据,因此合理的设置缓存区的大小很重要,注意发送缓冲区和接收缓冲区是两个缓存区,不是同一个。如下所示:

    int BufSize = 32 * 1024;
    result = setsockopt(iSocketServer, SOL_SOCKET, SO_SNDBUF, (CHAR *)&BufSize, sizeof(BufSize));
    if(result!= 0)
    {
        printf("Fail to set socket sendbuf options, errno = 0x%x!
    ", result);
    }
    
    int BufSize = 32 * 1024;
    result = setsockopt(iSocketServer, SOL_SOCKET, SO_RCVBUF, (CHAR *)&BufSize, sizeof(BufSize));
    if(result != 0)
    {
        printf("Fail to set socket recvbuf options, errno = 0x%x!
    ", result);
    }

    绑定socket

    如果socket作为服务端,那么必须的操作是绑定一个IP,且绑定时并不是一定就会成功,因此使用多次绑定的方法,如下所示:

    struct sockaddr_in6 ServerIp_V6 = {0x0};
    
    memset(&ServerIp_V6, 0x0, sizeof(struct sockaddr_in6));
    ServerIp_V6.sin6_family = AF_INET6;
    ServerIp_V6.sin6_port   = htons(9999);
    ServerIp_V6.sin6_addr   = in6addr_any;
    
    times = 0;
    while((result = bind(server, (struct sockaddr *)&ServerIp_V6, sizeof(struct sockaddr_in6))) != 0 && times < 0x3)
    {
        times++;
        printf("Bind socket faild %d times
    ", times);    
    }

     监听socket

    同绑定socket的操作,注意最大监听个数的选择,如下所示:

    times = 0;
    listenMax = 0x10;
    while ((lResultCode = listen(server, listenMax)) != 0 && times < 0x3)
    {
        times++;
        printf("[tkQxPotnDaemon] listen socket faild %d times
    ", times);
    }

    等待客户端连接

    服务端一切设置好之后,就需要调用accpet阻塞式等待客户端来连接,如下所示:

    struct sockaddr_in6 ManagerIp_v6 = {0x0};
    int AddrLen = sizeof(struct sockaddr_in6);
    while(1)
    {
        memset(&ManagerIp_v6, 0x0, sizeof(struct sockaddr_in6));
        AcceptSocket = accept(server, (struct sockaddr *)&ManagerIp_v6, (socklen_t *)&AddrLen);
        if (AcceptSocket < 0)
        {
            continue;
        }
        
        // 注意:ip是ManagerIp_v6.sin6_addr中的12、13、14、15位
        // 如:ManagerIp_v6.sin6_addr[12]、ManagerIp_v6.sin6_addr[13]、ManagerIp_v6.sin6_addr[14]、ManagerIp_v6.sin6_addr[15]
        
        // 注意:端口号是htons(ManagerIp_v6.sin6_port)
        
        // 进行数据通信
    }
  • 相关阅读:
    嵌套函数
    大括号{ }
    不是俺的错
    hasOwnProperty()
    属性的查找过程
    原型和原型链——汤姆大叔
    JS问题汇总
    phpcms无刷新分页
    phpcms开发过程中遇到的问题总结
    基于物联网的自动氮吹仪
  • 原文地址:https://www.cnblogs.com/chusiyong/p/12148043.html
Copyright © 2011-2022 走看看