基于libevent的长连接Android 推送服务器 1

目前来说,多数的app都是具有推送功能。目前也有很多第三方的推送服务平台提供sdk集成的方案。

但实际运用的时候发现,如果自身的业务比较复杂,第三方平台提供的api也很难进行集成。也许自己开发一个推送服务器是一种重复造轮子的行为,

但轮子总归是有尺寸、材料等各方面的差异,自己造一个轮子是为了更好的跑,跑的更远。


目前来说,实现推送功能有几种方法。

第一种是后台轮询,轮询的频率越高,设备电池消耗的越快,而且也无法保证消息能够及时到达。

第二种方式是简历一个长连接,手机与服务器之间保持连接,通过心跳机制来维系连接。

第三种方式是通过udp方式来进行推送。


第一种方式弊端明显,第二种方式相较于第三种方式,好处在于更容易实现,udp需要考虑穿透、自行实现可靠数据传输等机制,在开发工作量远远大于第二种方式。


折衷的方案采取socket长连接。我们采用的是linux服务器,linux实际是限制了进程能够打开的最大连接数,通过如下命令可以查看最大连接数:

ulimit -n

可以看到,centos这个数字是1024,也就是说,进程最大能够打开1024个文件,也就是,套接字程序单进程最多只能允许开启1024个连接。


linux系统下,可以自行修改这个值。此处不介绍如何修改这个参数。


为何要使用libevent?

libevent是一个事件库。

在使用libevent之前,我们编写网络应用程序,通常都是阻塞式的

#include <netdb.h>

#include <unistd.h>
#include <string.h>
#include <stdio.h>

int main(int c, char **v)
{
    const char query[] =
        "GET / HTTP/1.0\r\n"
        "Host: www.baidu.com\r\n"
        "\r\n";
    const char hostname[] = "www.baidu.com";
    struct sockaddr_in sin;
    struct hostent *h;
    const char *cp;
    int fd;
    ssize_t n_written, remaining;
    char buf[1024];

    /* Look up the IP address for the hostname.   Watch out; this isn't
       threadsafe on most platforms. */
    h = gethostbyname(hostname);
    if (!h) {
        fprintf(stderr, "Couldn't lookup %s: %s", hostname, hstrerror(h_errno));
        return 1;
    }
    if (h->h_addrtype != AF_INET) {
        fprintf(stderr, "No ipv6 support, sorry.");
        return 1;
    }

    /* Allocate a new socket */
    fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
        perror("socket");
        return 1;
    }

    /* Connect to the remote host. */
    sin.sin_family = AF_INET;
    sin.sin_port = htons(80);
    sin.sin_addr = *(struct in_addr*)h->h_addr;
    if (connect(fd, (struct sockaddr*) &sin, sizeof(sin))) {
        perror("connect");
        close(fd);
        return 1;
    }

    /* Write the query. */
    /* XXX Can send succeed partially? */
    cp = query;
    remaining = strlen(query);
    while (remaining) {
      n_written = send(fd, cp, remaining, 0);
      if (n_written <= 0) {
        perror("send");
        return 1;
      }
      remaining -= n_written;
      cp += n_written;
    }

    /* Get an answer back. */
    while (1) {
        ssize_t result = recv(fd, buf, sizeof(buf), 0);
        if (result == 0) {
            break;
        } else if (result < 0) {
            perror("recv");
            close(fd);
            return 1;
        }
        fwrite(buf, 1, result, stdout);
    }

    close(fd);
    return 0;
}

上面代码中,关于网络请求的代码均采用block io的模式,gethostbyname直到正确的解析了域名才有返回,connect需要一直等到真正连接了才能返回,recv一直到有数据传输才会接收数据。

send也需要一直等待,可见,阻塞IO是一种很简单同样也是很低效的方案。

libevent是一个非常有用的事件库,我们的推送服务也采用这个库来解决io和提升性能,目标是达到单台服务器百万级别的连接。





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值