博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ReplayKit2 有线投屏项目-反向Socket实现
阅读量:4942 次
发布时间:2019-06-11

本文共 5659 字,大约阅读时间需要 18 分钟。

一、需求

  我们在使用RTMP协议进行推流的时候,底层仍然采用的是TCP协议或者QUICK协议,有客户端主动发起请求。但是在有线投屏中,需要PC端向手机发起请求建立连接

 

二、实现

  在客户端主动发起请求之前,我们首先启动一个socket监听来自PC的连接,如果连接成功,那么我们使用这个已经建立好的连接,继续后面的流程

  在实现中,我们需要设计一个超时的机制,一般socket可以对send和recv设置超时,当然超时都是对同步的socket生效的。

  正常设置如下:

struct timeval tv, recv_timeout;   tv.tv_sec = timeout / 1000;   tv.tv_usec = static_cast
(timeout % 1000 * 1000); int ret = ::setsockopt(m_nRealServerSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*) &tv, sizeof(tv)); ret = ::setsockopt(m_nRealServerSocket, SOL_SOCKET, SO_SNDTIMEO, (const char*) &tv, sizeof(tv));

  但是这个设置对accept在iOS平台是不生效的,必须采用select的方式

  select监听描述符如下所示

#define MYPORT 1937    // the port users will be connecting to#define BACKLOG 1     // how many pending connections queue will hold#define BUF_SIZE 200int fd_A[BACKLOG];     // accepted connection fdint conn_amount;    // current connection amount- (void)startSelectDemo2{    int sock_fd, new_fd;  // listen on sock_fd, new connection on new_fd    struct sockaddr_in server_addr;    // server address information    struct sockaddr_in client_addr; // connector's address information    socklen_t sin_size;    int yes = 1;    char buf[BUF_SIZE];    int ret;    int i;        if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {        NSLog(@"socket");        exit(1);    }        if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {        NSLog(@"setsockopt");        exit(1);    }        server_addr.sin_family = AF_INET;         // host byte order    server_addr.sin_port = htons(MYPORT);     // short, network byte order    server_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP    memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero));        if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {        NSLog(@"bind");        exit(1);    }        if (listen(sock_fd, BACKLOG) == -1) {        NSLog(@"listen");        exit(1);    }        NSLog(@"listen port %d\n", MYPORT);        fd_set fdsr;    int maxsock;    struct timeval tv;        conn_amount = 0;    sin_size = sizeof(client_addr);    maxsock = sock_fd;    while (1) {        // initialize file descriptor set        FD_ZERO(&fdsr);        FD_SET(sock_fd, &fdsr);                // timeout setting        tv.tv_sec = 5;        tv.tv_usec = 0;                // add active connection to fd set        for (i = 0; i < BACKLOG; i++) {            if (fd_A[i] != 0) {                FD_SET(fd_A[i], &fdsr);            }        }                ret = select(maxsock + 1, &fdsr, NULL, NULL, &tv);        if (ret < 0) {            NSLog(@"select");            break;        } else if (ret == 0) {            NSLog(@"timeout\n");            continue;        }                // check every fd in the set        for (i = 0; i < conn_amount; i++) {            if (FD_ISSET(fd_A[i], &fdsr)) {                ret = recv(fd_A[i], buf, sizeof(buf), 0);                if (ret <= 0) {        // client close                    NSLog(@"client[%d] close\n", i);                    close(fd_A[i]);                    FD_CLR(fd_A[i], &fdsr);                    fd_A[i] = 0;                } else {        // receive data                    if (ret < BUF_SIZE)                        memset(&buf[ret], '\0', 1);                    NSLog(@"client[%d] send:%s\n", i, buf);                }            }        }                // check whether a new connection comes        if (FD_ISSET(sock_fd, &fdsr)) {            new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);            if (new_fd <= 0) {                NSLog(@"accept");                continue;            }            else            {                const char *hello = "hello from clent";                send(new_fd, hello, strlen(hello), 0);                                char recvbuf[4096];                int retry = 0;                while (retry++ < 3) {                                        memset(recvbuf, 0, 4096);                                        int ret = recv(new_fd, recvbuf, 4096 - 1, 0);                                        if(ret > 0)                    {                        NSLog(@"app recv:%s\n",recvbuf);                    }                    else                    {                        NSLog(@"app recv error ret = %d\n",ret);                    }                }                                            }                        // add to fd queue            if (conn_amount < BACKLOG) {                fd_A[conn_amount++] = new_fd;                NSLog(@"new connection client[%d] %s:%d\n", conn_amount,                       inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));                if (new_fd > maxsock)                    maxsock = new_fd;            }            else {                NSLog(@"max connections arrive, exit\n");                send(new_fd, "bye", 4, 0);                close(new_fd);                break;            }        }                int i;        NSLog(@"client amount: %d\n", conn_amount);        for (i = 0; i < BACKLOG; i++) {            NSLog(@"[%d]:%d  ", i, fd_A[i]);        }        NSLog(@"\n\n");    }        // close other connections    for (i = 0; i < BACKLOG; i++) {        if (fd_A[i] != 0) {            close(fd_A[i]);        }    }        exit(0);}

  在成功收到连接之后,我们确保连接变成同步方式

unsigned long ul = 0;ioctl(Sock, FIONBIO, &ul)

  并且在recv的时候,最后一个参数也可以决定是否是同步还是异步的方式,0 表示默认方式 ; 0x80表示异步的方式

ssize_t    recv(int, void *, size_t, int) __DARWIN_ALIAS_C(recv);

  

三、总结

 

  对于理解网络底层的编程,理解select的工作原理还需要继续加深。

 

四、代码

https://github.com/liqiushui/iOSSocketAcceptTimeout

转载于:https://www.cnblogs.com/doudouyoutang/p/9186280.html

你可能感兴趣的文章
NSSet和NSArray区别与方法总结
查看>>
Python列表 元组 字典 集合
查看>>
foreach遍历数组、数组的转置与方阵的迹
查看>>
Still unable to dial persistent://blog.csdn.net:80 after 3 attempts
查看>>
HTML超文本标记语言(九)——表单输入类型
查看>>
基于busybox制作mini2440根文件系统及使用nfs挂载
查看>>
信道容量及信道编码原理学习
查看>>
浅谈独立特征(independent features)、潜在特征(underlying features)提取、以及它们在网络安全中的应用...
查看>>
从随机过程的熵率和马尔科夫稳态过程引出的一些思考 - 人生逃不过一场马尔科夫稳态...
查看>>
《A First Course in Abstract Algebra with Applications》-chaper1-数论-关于素数
查看>>
ORA-3136
查看>>
算法笔记_145:拓扑排序的应用(Java)
查看>>
JS获取农历日期
查看>>
PHP中的HTTP协议
查看>>
CSS给文字描边实现发光文字
查看>>
Java WebService入门实例
查看>>
css样式之补充
查看>>
结构与联合
查看>>
关于JS历史
查看>>
软件架构师工作流程
查看>>