一、需求

  我们在使用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<int>(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 200
int fd_A[BACKLOG]; // accepted connection fd
int 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

p.p1 { margin: 0; font: 26px Menlo; color: rgba(139, 132, 207, 1); background-color: rgba(40, 43, 53, 1) }

ReplayKit2 有线投屏项目-反向Socket实现的更多相关文章

  1. mac电脑怎么投屏?教你选择适合自己的Mac投屏软件

    mac上有什么好的投屏软件嘛?苹果手机ios投屏到mac用哪款投屏软件,mac投屏ipad该用哪款软件怎么操作,macdown小编给大家介绍的这几款Mac投屏软件,各有各的特色,总有一款适合你投屏. ...

  2. 看完小白也会使用,Android投屏神器scrcpy详细教程

    楔子 做为一个软件测试工程师,在使用手机测试的时候,缺陷附件想附上截图.视频,需要从手机把图片.视频发送到拷贝或发送到电脑,非常麻烦. 所以想到使用投屏软件,把手机的屏幕投屏到电脑,便可以直接在电脑上 ...

  3. ios11苹果手机怎么投屏到电脑

    使用过苹果手机的用户都知道,苹果手机触摸屏操作极为流畅,网页浏览也非常轻松,各种网络上的应用可以说是非常完美.iPhone的娱乐功能相当的强大,能让苹果iPhone超越了其他手机很大的距离.但是手机怎 ...

  4. 安卓投屏助手(B1358)之辅助调试

    Android远程桌面助手的中文版——安卓投屏助手正式上线.安卓投屏和远程控制的软件其实已经非常多了,如Vysor.Total Control.Mobizen.ApowerMirror.TeamVie ...

  5. ios屏幕怎么投屏到电脑显示器

    iphone在国内一直都很受欢迎,为什么这么受欢迎呢?其实苹果手机操作系统非常的新颖,让人对手机有了重新的认识.但是ios屏幕怎么投屏到电脑显示器.感兴趣的一起阅读下面的内容吧! 使用工具: 苹果手机 ...

  6. 安卓手机如何快速投屏到windows(10/8.1/7)电脑上

    前提: 手机和电脑连接的网络必须在同一局域网下. 优势: 手机和电脑不需要下载对应平台的应用,完全使用全系统自带功能. 附加: 以下演示是安卓手机和windows操作系统电脑,并且win10和win1 ...

  7. iPhone手机怎么投屏到电脑上

    如今生活水平不断上升,人们更加追求高质量.高享受的生活,所以可以利用一切资源提高生活质量,享受更好的生活体验,比如说手机投屏电脑就可以提高我们的视觉体验,所以更多的人去尝试,那么iPhone手机怎么投 ...

  8. iPhone手机怎么投屏到电脑 airplay在哪里设置

    iPhone手机怎么投屏到电脑?想要小屏转大屏,其实方法很简单,简单几步就可以操作,下面简单几步教大家手机投屏电脑的方法. 使用工具: Iphone&电脑 操作方法: 1.如果想要把手机本地的 ...

  9. iphone屏幕镜像怎么用 手机投屏电脑

    手机看视频有的时候总会感觉到累,屏幕太小看的不够爽又或者用手一直拿着手机看累得慌.我就就喜欢看电视因为电视屏幕大看的爽,而且现在很多手机视频都可以往电视上投影视频,那么iphone屏幕镜像怎么用? 使 ...

  10. 苹果手机如何投屏到win10电脑上

    苹果手机中的IOS系统比安卓系统的确好用.苹果手机使用多久都不会出现手机卡顿的现象,一如既往的流畅自如,这就是人们追求苹果机的原因之一.苹果手机朋友们可能会觉得手机屏幕太小影响视觉怎么办,苹果手机如何 ...

随机推荐

  1. SpringCloud做的微服务项目--外卖订餐系统

    本项目用到的组件技术可以参考我上一篇博客,来学习. 项目需求: 客户端:针对普通用户,用户登录,用户退出,菜品订购,我的订单 后台管理系统:针对管理员,管理员登录,管理员退出,添加菜品,查询菜品,修改 ...

  2. 【笔记】join using&AVG

    oracle using 在oracle中,using用于简化连接查询,只有当查询是等值连接和连接中的列必须具有相同的名称与数据类型时,才能使用using关键字进行简化 比如原来是 select s. ...

  3. Lindorm-Operator云原生实践

    简介: Kubernetes 的CRD 机制(CustomResourceDefinition)支持通过自定义的controller来管理资源的生命周期,这样就可以像操作pod,deployment一 ...

  4. EasyNLP带你玩转CLIP图文检索

    简介: 本文简要介绍CLIP的技术解读,以及如何在EasyNLP框架中玩转CLIP模型. 作者:熊兮.章捷.岑鸣.临在 导读 随着自媒体的不断发展,多种模态数据例如图像.文本.语音.视频等不断增长,创 ...

  5. 阿里云消息队列 RocketMQ 5.0 全新升级:消息、事件、流融合处理平台

    ​简介: RocketMQ5.0 的发布标志着阿里云消息从消息领域正式迈向了"消息.事件.流"场景大融合的新局面.未来阿里云消息产品的演进也将继续围绕消息.事件.流核心场景而开展. ...

  6. 如何高效学习 Kubernetes 知识图谱?

    ​简介: Kubernetes 知识图谱遵循云原生人才学习路径搭建课程体系框架,及人才发展路线设置不同阶段,由浅入深,帮助云原生人才学习容器基础.Kuternetes 网络.存储.资源对象.服务发现. ...

  7. [Mobi] 什么是手机 Root 和 Magisk、Magisk App

    手机进行 Root 操作就是让我们能够拥有超级权限,包括被手机厂商所禁止的一些操作. 传统 Root 手段会修改系统文件,因而一些安全性要求较高的 App 会禁止自己在 Root 过的手机上运行. M ...

  8. win10 uwp 使用 XamlTreeDump 获取 XAML 树元素内容

    本文来安利大家 XamlTreeDump 库,通过这个库可以将 XAML 树上的元素转换为 json 字符串,可以用来进行 UI 单元测试 开始之前先通过 NuGet 工具安装 XamlTreeDum ...

  9. MSBuild 输出日志可视化工具 MSBuild Structured Log Viewer 简介

    感谢 Vatsan Madhavan 小伙伴推荐的 MSBuild 输出日志可视化工具,这个工具可以使用漂亮的 WPF 界面预览 MSBuild 复杂的输出内容 这是一个完全开源的工具,请看 Kiri ...

  10. Unity热更学习笔记--AB包的依赖 0.98

    AB包的依赖 接上一小结. 在这里我们新建一个红色材质球,赋值给Cube预制体.此时不对材质球进行AB包分类,再次进行打包.运行脚本,发现红色cube成功的从AB包中加载出来.尽管我们没有将cube所 ...