13-Openwrt libubox ustream

111 篇文章 10 订阅
87 篇文章 31 订阅

流缓冲管理,ustream_fd​​​跟​​uloop_fd​​​有什么不一样呢?​​ustream_fd​​​内部其实就是​​uloop_fd​​,与fopen和open类似,fopen的内部也是open加上流缓冲管理。

struct ustream_fd {
    struct ustream stream;
    struct uloop_fd fd;
};

ustream相关的函数

void ustream_fd_init(struct ustream_fd *s, int fd)

void ustream_init_defaults(struct ustream *s)

void ustream_free(struct ustream *s)


ustream的应用在uhttpd的socket监听里面有使用到

bool uh_accept_client(int fd, bool tls)
{
    static struct client *next_client;
    struct client *cl;
    unsigned int sl; 
    int sfd;
    static int client_id = 0;
    struct sockaddr_in6 addr;

    if (!next_client)
        next_client = calloc(1, sizeof(*next_client));

    cl = next_client;

    sl = sizeof(addr);
    sfd = accept(fd, (struct sockaddr *) &addr, &sl);
    if (sfd < 0)
        return false;

    set_addr(&cl->peer_addr, &addr);
    sl = sizeof(addr);
    getsockname(sfd, (struct sockaddr *) &addr, &sl);
    set_addr(&cl->srv_addr, &addr);

    cl->us = &cl->sfd.stream;
    if (tls) {
        uh_tls_client_attach(cl);
    } else {
        cl->us->notify_read = client_ustream_read_cb;
        cl->us->notify_write = client_ustream_write_cb;
        cl->us->notify_state = client_notify_state;
    }

    cl->us->string_data = true;
    ustream_fd_init(&cl->sfd, sfd);

    uh_poll_connection(cl);
    list_add_tail(&cl->list, &clients);

    next_client = NULL;
    n_clients++;
    cl->id = client_id++;
    cl->tls = tls;

    return true;
}


ustream在socket上面的使用例子:

//客户端//
#include "std.h"

/* 在TCP连接持续多少秒没有报文往来之后则开始发送探测报文 */
int tcp_keepalive_time = 5;
/* TCP keepalive探测包的发送间隔 */
int tcp_keepalive_intvl = 5;
/* 在tcp_keepalive_time之后没有收到对方确认,继续发送保活探测包的次数 */
int tcp_keepalive_probes = 3;

int fd = -1;
struct ustream_fd ufd;                      // uloop机制监听的结构体

static void notify_read_cb(struct ustream *s, int bytes)
{
    char *data = NULL;
    int len;

    data = ustream_get_read_buf(s, &len);
    printf("eason recv data:%d available len:%d", bytes, len);
    if(!data){
        printf("eason recv packet len is too short, wait more data");
        return;
    }

    ustream_consume(s, len);
}

/**************************************************************************************
* FunctionName   : notify_state_cb()
* Description    : uloop+ustream框架通知连接状态发生变化的回调,如果检测到对端断开则本地断开连接
* EntryParameter : 指向当前活跃的ustream的指针
* ReturnValue    : NULL
**************************************************************************************/
static void notify_state_cb(struct ustream *s)
{
    if (!s->eof) return;
    printf("eason misock client got eof!, pending:%d", s->w.data_bytes);
    close(fd);
}

/**************************************************************************************
* FunctionName   : notify_write_cb()
* Description    : uloop+ustream框架通知缓冲数据已经被写入到stream中
* EntryParameter : 指向当前活跃的ustream的指针
* ReturnValue    : NULL
**************************************************************************************/
static void notify_write_cb(struct ustream *s, int bytes)
{
    printf("eason misock client wrote:%d bytes, pending:%d", bytes, s->w.data_bytes);
}

static void setup_misock_client_ustream()
{
    ufd.stream.string_data  = false;
    ufd.stream.notify_read  = notify_read_cb;
    ufd.stream.notify_state = notify_state_cb;
    ufd.stream.notify_write = notify_write_cb;
    ustream_fd_init(&ufd, fd);
}

int main(void)
{
    struct sockaddr_in server;
    int optval;
    struct timeval tval;
    fd_set r_set, w_set;
    int rc = 0;

    // 1.创建
    if (0 > (fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))
        err_exit("socket");

    // 2.模式
    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); //设置非阻塞模式

    // 3.绑定

    // 4.连接
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(8888);
    server.sin_addr.s_addr = inet_addr("192.168.201.130");
    if (0 > connect(fd, (struct sockaddr *)&server, sizeof(server)))
        err_exit("connect");
    printf("connect success!\n");


    /* 4.KEEPALIVE相关配置 */
    /*使能keepalive*/
    optval =1;
    setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
    /* 配置tcp_keepalive_time */
    optval = tcp_keepalive_time;
    setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &optval, sizeof(optval));
    /* 配置tcp_keepalive_intvl */
    optval = tcp_keepalive_intvl;
    setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &optval, sizeof(optval));
    /* 配置tcp_keepalive_probes */
    optval = tcp_keepalive_probes;
    setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &optval, sizeof(optval));

    // 4.确定连接已经成功
    FD_ZERO(&r_set);
    FD_SET(fd, &r_set);
    FD_ZERO(&w_set);
    FD_SET(fd, &w_set);
    tval.tv_sec  = 1;
    tval.tv_usec = 0;

    rc = select(fd+1, &r_set, &w_set, NULL, &tval);
    if(rc <= 0){
        printf("eason fun=%s,line=%d", __FUNCTION__,__LINE__);
        goto RETURN_1;
    }

    printf("eason connect fd=%d,%d,%d,%d",fd,rc,FD_ISSET(fd, &w_set),FD_ISSET(fd, &r_set));
    if (rc == 1 && FD_ISSET(fd, &w_set) && !FD_ISSET(fd, &r_set)) {
        printf("eason connected\n");
        setup_misock_client_ustream();
        return NULL; // connected
    }
    printf("eason connect failed fun=%s,line=%d", __FUNCTION__,__LINE__);

RETURN_1:
    // 10.关闭
    close(fd);
    return NULL;

#if 0   
    char send_buf[BUFSIZ];
    char recv_buf[BUFSIZ];
    int maxfd= -1;
    fd_set readfds;
    int ret=-1;
    int i;

    while(1) {
        FD_ZERO(&readfds);

        FD_SET(0, &readfds);
        maxfd = maxfd > 0 ? maxfd : 0;
        FD_SET(connfd, &readfds);
        maxfd = maxfd > connfd ? maxfd : connfd;

        if (0 > select(maxfd + 1, &readfds, NULL, NULL, NULL))
            err_exit("select");

        for (i=0; i<=maxfd; i++) 
        {
            if (FD_ISSET(i, &readfds)) 
            {
                if (0 == i) 
                {
                    fgets(send_buf, sizeof(send_buf), stdin);       
                    if (0 > send(connfd, send_buf, strlen(send_buf) + 1, 0))
                        err_exit("send");               
                } 
                else if (connfd == i) 
                {
                    if (0 > (ret = recv(connfd, recv_buf, BUFSIZ, 0)))
                        err_exit("recv");
                    else if (0 == ret) 
                    {
                        printf("server quit!\n");
                        exit(0);
                    }

                    recv_buf[ret] = '\0';
                    printf("server: %s\n", recv_buf);
                }
            }
        }
    }
    close(connfd);
    exit(0);
#endif  
}


另外在libubox里面也有自带一个例子:

位于/example/ustream-example.c

#include <sys/socket.h>
#include <netinet/in.h>

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

#include "ustream.h"
#include "uloop.h"
#include "usock.h"

static struct uloop_fd server;
static const char *port = "10000";
struct client *next_client = NULL;

struct client {
  struct sockaddr_in sin;

  struct ustream_fd s;
  int ctr;
};

static void client_read_cb(struct ustream *s, int bytes)
{
  struct client *cl = container_of(s, struct client, s.stream);
  struct ustream_buf *buf = s->r.head;
  char *newline, *str;

  do {
    str = ustream_get_read_buf(s, NULL);
    if (!str)
      break;

    newline = strchr(buf->data, '\n');
    if (!newline)
      break;

    *newline = 0;
    ustream_printf(s, "%s\n", str);
    ustream_consume(s, newline + 1 - str);
    cl->ctr += newline + 1 - str;
  } while(1);

  if (s->w.data_bytes > 256 && !ustream_read_blocked(s)) {
    fprintf(stderr, "Block read, bytes: %d\n", s->w.data_bytes);
    ustream_set_read_blocked(s, true);
  }
}

static void client_close(struct ustream *s)
{
  struct client *cl = container_of(s, struct client, s.stream);

  fprintf(stderr, "Connection closed\n");
  ustream_free(s);
  close(cl->s.fd.fd);
  free(cl);
}

static void client_notify_write(struct ustream *s, int bytes)
{
  fprintf(stderr, "Wrote %d bytes, pending: %d\n", bytes, s->w.data_bytes);

  if (s->w.data_bytes < 128 && ustream_read_blocked(s)) {
    fprintf(stderr, "Unblock read\n");
    ustream_set_read_blocked(s, false);
  }
}

static void client_notify_state(struct ustream *s)
{
  struct client *cl = container_of(s, struct client, s.stream);

  if (!s->eof)
    return;

  fprintf(stderr, "eof!, pending: %d, total: %d\n", s->w.data_bytes, cl->ctr);
  if (!s->w.data_bytes)
    return client_close(s);

}

static void server_cb(struct uloop_fd *fd, unsigned int events)
{
  struct client *cl;
  unsigned int sl = sizeof(struct sockaddr_in);
  int sfd;

  if (!next_client)
    next_client = calloc(1, sizeof(*next_client));

  cl = next_client;
  sfd = accept(server.fd, (struct sockaddr *) &cl->sin, &sl);
  if (sfd < 0) {
    fprintf(stderr, "Accept failed\n");
    return;
  }

  cl->s.stream.string_data = true;
  cl->s.stream.notify_read = client_read_cb;
  cl->s.stream.notify_state = client_notify_state;
  cl->s.stream.notify_write = client_notify_write;
  ustream_fd_init(&cl->s, sfd);
  next_client = NULL;
  fprintf(stderr, "New connection\n");
}

static int run_server(void)
{

  server.cb = server_cb;
  server.fd = usock(USOCK_TCP | USOCK_SERVER | USOCK_IPV4ONLY | USOCK_NUMERIC, "127.0.0.1", port);
  if (server.fd < 0) {
    perror("usock");
    return 1;
  }

  uloop_init();
  uloop_fd_add(&server, ULOOP_READ);
  uloop_run();

  return 0;
}

static int usage(const char *name)
{
  fprintf(stderr, "Usage: %s -p <port>\n", name);
  return 1;
}

int main(int argc, char **argv)
{
  int ch;

  while ((ch = getopt(argc, argv, "p:")) != -1) {
    switch(ch) {
    case 'p':
      port = optarg;
      break;
    default:
      return usage(argv[0]);
    }
  }

  return run_server();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值