分类 FastDFS 下的文章

FastDFS日志系统分析

0.为什么要有日志

在软件开发从业者眼中,日志的重要性应该是不言而喻的。浅显的说,日志的作用体现在如下几个场景:

  1. 其实我们大部分人写的第一个程序Hello World就是一条日志,只不过该日志直接输出到了屏幕上。它告诉我们,程序按照我们的意愿执行了。
  2. 慢慢我们的代码行数开始变多,终于可以写个几十上百行的程序了。代码中也开始有逻辑有算法了,但在解决了一堆编译错误后,从会遇到程序执行的结果不是我们想要的情况。经过一番推测,我们觉得是变量i的值在这个时刻不对,但这只是猜测而已,为了印证,不如把i的值在程序运行到此刻打印出来看看?
  3. 我们学会了GDB或其他调试工具,渐渐的觉得用打印的手段来调试有些太弱了。开始不太好意思跟别人在别人面前往代码中插入printf语句了。
  4. 终于我们的代码行数越来越多,逻辑越来越复杂。一个程序分的执行分成了很多个阶段,各种回调函数满天飞,我们的程序也不再是从上到下一条线执行了,不仅有多进程,还有多线程。出了问题,祭出GDB。每次都要GDB进去,设断点,设置跟踪子进程、挂载线程...更有可能,问题并不能复现。身心疲惫。
  5. 同时我们也在接触一些稍微复杂些的开源软件。出了问题发邮件去请教别人,往往得到的第一句回答是:“把XXX的log发过来看下。”

- 阅读剩余部分 -

AF_INET与PF_INET的区别

在一些开源项目的socket相关代码中,会同时看到AF_IENT和PF_INET,这两者有什么区别呢?

其实这两个东西就是当年设计上的误差而已。AF=Adress Family;PF=Protocal Family,原来的设计是设想一个AF会支持多个PF,但是就没有然后了。现在为止,这两个东西就是一样的,Linux源代码为证:

/* Protocol families, same as address families. */
#define PF_UNSPEC   AF_UNSPEC
#define PF_UNIX  AF_UNIX
#define PF_LOCAL    AF_LOCAL
#define PF_INET  AF_INET

参考:
http://stackoverflow.com/questions/6729366/what-is-the-difference-between-af-inet-and-pf-inet-in-socket-programming

linux下获取本地ip的几种方法

1.调用getifaddrs

The getifaddrs() function first appeared in glibc 2.3, but before glibc 2.3.3, the implementation supported only IPv4 addresses; IPv6 support was added in glibc 2.3.3. Support of address families other than IPv4 is available only on kernels that support netlink.

int getlocaladdrs(char ip_addrs[][IP_ADDRESS_SIZE], \
    const int max_count, int *count)
{
    struct ifaddrs *ifc;
    struct ifaddrs *ifc1;

    *count = 0;
    if (0 != getifaddrs(&ifc))
    {
        logError("file: "__FILE__", line: %d, " \
            "call getifaddrs fail, " \
            "errno: %d, error info: %s", \
            __LINE__, errno, STRERROR(errno));
        return errno != 0 ? errno : EMFILE;
    }
<!--more-->
    ifc1 = ifc;
    while (NULL != ifc)
    {
        struct sockaddr *s;
        s = ifc->ifa_addr;
        if (NULL != s && AF_INET == s->sa_family)
        {
            if (max_count <= *count)
            {
                logError("file: "__FILE__", line: %d, "\
                "max_count: %d < iterface count: %d", \
                __LINE__, max_count, *count);
                freeifaddrs(ifc1);
                return ENOSPC;
            }

            if (inet_ntop(AF_INET, &((struct sockaddr_in *)s)-> \
            sin_addr, ip_addrs[*count], IP_ADDRESS_SIZE) != NULL)
            {
                (*count)++;
            }
            else
            {
                logWarning("file: "__FILE__", line: %d, " \
                    "call inet_ntop fail, " \
                    "errno: %d, error info: %s", \
                    __LINE__, errno, STRERROR(errno));
            }
        }

        ifc = ifc->ifa_next;
    }

    freeifaddrs(ifc1);
    return *count > 0 ? 0 : ENOENT;
}

2.调用ioctl

int getlocaladdrs(char ip_addrs[][IP_ADDRESS_SIZE], \
    const int max_count, int *count)
{
    int s;
    struct ifconf ifconf;
    struct ifreq ifr[32];
    int if_count;
    int i;
    int result;

    *count = 0;
    s = socket(AF_INET, SOCK_STREAM, 0);
    if (s < 0)
    {
        logError("file: "__FILE__", line: %d, " \
            "socket create fail, errno: %d, error info: %s", \
            __LINE__, errno, STRERROR(errno));
        return errno != 0 ? errno : EMFILE;
    }

    ifconf.ifc_buf = (char *) ifr;
    ifconf.ifc_len = sizeof(ifr);
    if (ioctl(s, SIOCGIFCONF, &ifconf) < 0)
    {
        result = errno != 0 ? errno : EMFILE;
        logError("file: "__FILE__", line: %d, " \
            "call ioctl fail, errno: %d, error info: %s", \
            __LINE__, result, STRERROR(result));
        close(s);
        return result;
    }

    if_count = ifconf.ifc_len / sizeof(ifr[0]);
    if (max_count < if_count)
    {
        logError("file: "__FILE__", line: %d, " \
            "max_count: %d < iterface count: %d", \
            __LINE__, max_count, if_count);
        close(s);
        return ENOSPC;
    }

    for (i = 0; i < if_count; i++)
    {
        struct sockaddr_in *s_in;
            s_in = (struct sockaddr_in *) &ifr[i].ifr_addr;
            if (!inet_ntop(AF_INET, &s_in->sin_addr, \
            ip_addrs[*count], IP_ADDRESS_SIZE))
        {
            result = errno != 0 ? errno : EMFILE;
            logError("file: "__FILE__", line: %d, " \
                "call inet_ntop fail, " \
                "errno: %d, error info: %s", \
                __LINE__, result, STRERROR(result));
            close(s);
            return result;
            }
        (*count)++;
    }

    close(s);
    return *count > 0 ? 0 : ENOENT;
}

3.判断一个ip是否是本地ip的几种方法:

(1)用该ip和指定一个端口号,执行bind操作,成功则说明是本地IP,否则不是。

(2)上一种方法的问题在于,如果指定的端口被占用了,那么及时是本地Ip,bind也会出错。可以做如下修改:bind时指定0端口,让系统给分配一个可用的端口。

(3)先用上面提到的获取本地Ip的两种方法把本地ip列表获取到,然后看目标ip是否在其中即可。

- 阅读剩余部分 -