使用sunshine和moonlight实现远程游戏串流

news/发布时间2024/9/20 6:08:36

过年回家想要打游戏,但是苦于家里没有电脑,又没办法把电脑搬回去,于是想到了使用串流的方式。

实现串流的软件有多种:

  1. moonlight。因为仅实现了 NVIDIA 的游戏串流协议,所以只支持 N 卡。
  2. Steam Link。支持 steam 的游戏。
  3. Sunshine。支持 AMD, Intel, 和 Nvidia 三家的显卡。而且支持使用 Moonlight 作为客户端。开源。
  4. Parsec。其实是一个远程桌面的商业解决方案,不仅仅能用来打游戏。需要注册账号且闭源。

因为使用的是 A 卡,而且玩的不只是 steam 游戏,经过综合的考虑,选择了 Sunshine 作为串流工具。

Sunshine 的安装

首先需要在官网下载 Sunshine,安装后设置开机启动。

如果启动时命令行窗口提示

Terminate called after throwing an instance of 'std::range_error'what():  wstring_convert::from_bytes

则需要通过 Win+S 输入【区域】并进入区域设置,点击【管理】标签页,然后点击【更改系统区域设置】,勾选【Beta 版:使用 Unicode UTF-8 提供全球语言支持】,重启电脑。

请添加图片描述

ipv6

想要从外网访问主机,有两种方式,一种是公网 ip,一种是内网穿透。

公网的 ipv4 需要向运营商申请,因为 ipv4 稀缺的原因,所以很难申请到。但是 ipv6 可以让全球每台设备都拥有一个可访问的公网地址。

首先访问 IPv6 测试 测试是否支持 ipv6,如果显示 DNS 服务器已经配置 IPv6,说明营运商已经接入 ipv6,这时候只需要找到路由器,打开 ipv6 开关便可。
请添加图片描述

现在大多数运营商都已经接入 ipv6,除了
个别 (说的就是广电网络),没有接入的话,需要打电话给运营商开通。

连接上 ipv6 网络后,可以通过访问 ipv6 网站获取可访问的外网 ipv6 地址,也可以通过 ipconfig /all 命令获取。

请添加图片描述

DDNS

运营商出于安全考虑,并不会给固定的 ipv6 地址,每次拨号后或者电脑重启后,ip 地址都会改变,导致每次都要手动获取当前的 ipv6 地址。一种解决办法是使用 DDNS(动态域名解析),将 ip 地址映射到固定的域名地址,并检测每次 ip 地址的变更,重新进行映射。部分路由器会提供 DDNS 功能,我们需要注册一个路由器支持的 DDNS 提供商的账号。

下面以 no-ip 为例。

先去官网注册一个账号 Free Dynamic DNS No-IP,然后新建一个域名,Record Type 选择 ipv6,再把主机的 ipv4 和 ipv6 地址填上去。
请添加图片描述

新建好域名后,把账号信息填到路由器上的 DDNS 功能上,便可使用。

如果路由器不支持 DDNS 咋办?这就需要使用脚本动态监听 ip 地址的更改,并修改映射。

下面是一个使用 python 实现一个定时获取本机 ipv6 地址。然后通过 no-ip 的 api 修改映射的脚本。

import socket
import base64
import os
import re
import timeclass netParam:def __init__(self):self.host = "xxx"self.usrname = "xxx"self.passwd = "xxx"self.domain = "xxx"self.timeval = 10 * 60self.server_port = 80def getIPv6Address():host_ipv6=[]ips=socket.getaddrinfo(socket.gethostname(),80)for ip in ips:if ip[4][0].startswith('24'):# 2408 中国联通# 2409 中国移动# 240e 中国电信return ip[4][0]def getip(domain):address = socket.getaddrinfo(domain, 'http')return address[0][4][0]if __name__ == "__main__":param = netParam()tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)tcp_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # 不经过WAIT_TIME,直接关闭tcp_sock.setblocking(False)                                     # 设置非阻塞编程tcp_sock.settimeout(1)link_statu = Falsesend_data_len = 0old_ipv6addr = ""fisrt_flag = True# 按协议,对usrname:passwd进行base64编码raw_key = param.usrname + ":" + param.passwdprint("raw key: " + raw_key)encode_key = base64.b64encode(raw_key.encode("utf-8"))encode_key = str(encode_key)[2:len(str(encode_key)) - 1]print("encode key: " + encode_key)#构造请求头部的内容,由于本机ip可能变化,因此这里没有直接把GET方法写进去,而是放在循环体中做requestParam = ""requestParam += "Host: dynupdate.no-ip.com\r\n"requestParam += "Authorization: Basic " + encode_key + "\r\n"requestParam += "User-Agent: None\r\n\r\n"print("request:\n" + requestParam)while(True):# 每次运行等待timeval(此处是5分钟)的间隔,避免频繁更新if (True != fisrt_flag):time.sleep(param.timeval)fisrt_flag = False# 获取ipv6地址,若地址没有发生改变,则不上报更新ipv6addr = getIPv6Address()if (0 != len(ipv6addr)):print("ipv6 addr: " + ipv6addr)if (ipv6addr == old_ipv6addr):print("ip not change, continue")continue# 构造请求的头部GET方法内容requestHead = "GET "requestHead += "/nic/update?hostname=" + param.domain + "&myip=" + ipv6addr + " HTTP/1.1\r\n"# 建立tcp连接if (False == link_statu):server_ip = getip(param.host)print("server ip is :" + server_ip)try:tcp_sock.connect((server_ip, param.server_port))print("connect server success")link_statu = Trueexcept Exception as err:print("connect server failed, exception:", err)continue# 发送数据send_data = requestHead + requestParamsend_data_len = 0while send_data_len < len(send_data):time.sleep(0.1)try:send_data_len += tcp_sock.send(send_data[send_data_len:].encode())print("send " + str(send_data_len) + " data")except Exception as err:print("send data error, exception: ", err)print("close tcp socket")tcp_sock.close()link_statu = Falsebreakif (send_data_len != len(send_data)):continueprint("send data:" + send_data)# 检查结果,更新成功则把当前ip记录为旧ipif (True == link_statu):try:recv_data = tcp_sock.recv(2048)print("server reply:\n" + str(recv_data))except Exception as err:print("recv data error, exception: ", err)tcp_sock.close()link_statu = Falseif (-1 != str(recv_data).find("HTTP/1.1 200 OK")):old_ipv6addr = ipv6addrprint("update ip success")print("end")

最好将脚本设置开机启动。

防火墙

在成功设置域名访问后,会发现依旧无法访问主机,这是因为路由器和主机上都设置了防火墙,阻止外来网络的恶意访问。所以我们需要关闭路由器的防火墙,设置 window 防火墙开放 moonlight 的端口。端口为:

  • TCP: 47984, 47989, 48010
  • UDP: 47998-48000, 48002, 48010

开放 window 的防火墙的特定端口,首先 win 键搜索“高级安全 Windows Defender 防火墙”,选择入站规则 ->新建规则 ->端口。

请添加图片描述

选择 UDP 或 TCP,输入特定端口。
请添加图片描述

到此,便可从外网访问到内网主机。

内网穿透

但如果控制端和被控制端任何一方不存在 ipv6,则只能使用内网穿透,内网穿透可以使用 zerotier,使用办法也很简单,注册一个账号,然后新建一个网络,得到一个网络 ID,分别下载 window 和安卓端的软件,添加网络 ID,便可以使用。在网络的设置页面能看到给成员分配的 ipv4 地址,可以通过这个 ipv4 地址互相访问。

智能插座与主板来电启动

解决了上述问题后,远程问题是解决了,但是电脑不可能一直开着,这时候可以使用智能插座或者开机棒,如果是小米智能插座,可以直接连 wifi,如果是小米智能插板,则另外需要一个网关。特别需要注意的是,在电脑关机后,一定要多等几分钟确定功率为 0 后再关闭插座,防止电脑突然断电。

然后设置主板的来电启动,这个需要参考不同主板的设置。

显卡欺骗器

还有问题就是,显示器关闭状态下,显卡是不会工作的,这会导致串流时显示黑屏,解决办法是购买一个 HDMI 显卡欺骗器,或者网上下载一个虚拟现实器的软件,从而实现显示器关闭后,显卡也能正常工作。

最后

准备工作做好后,最后便是下载 moonlight手机端,通过域名连上电脑,开开心心打游戏。

建议最好是把向日葵也设置开启启动,防止出现问题时也能远程连接上电脑。

参考:

  1. Sunshine error at launch · Issue #1446 · LizardByte/Sunshine · GitHub
  2. GitHub - LizardByte/Sunshine: Self-hosted game stream host for Moonlight.
  3. DDNS No-IP自动更新IPv6地址的的Python脚本-CSDN博客
  4. No-ip ddns动态域名解析 - 简书
  5. create-hostname-ipv6-address-aaaa-record-support-question-day
  6. ZeroTier | Global Area Networking

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.bcls.cn/nWQF/9757.shtml

如若内容造成侵权/违法违规/事实不符,请联系编程老四网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

Flutter Text 下划线

IntrinsicWidth(child: Column(mainAxisAlignment:MainAxisAlignment.center,children: [Text("工单名称",style: TextStyle(overflow: TextOverflow.fade,color: AppColors.baseColor,fontSize: 15.sp,// decorationStyle: TextDecorationStyle.dashed),),Container…

Win11系统安装安卓子系统教程

随着Win11系统的不断普及&#xff0c;以及硬件设备的更新换代&#xff0c;我相信很多同学都已经更新并使用到了最新的Win11系统。那么&#xff0c;Win11系统最受期待的功能“Windows Subsystem for Android”&#xff08;简称WSA&#xff09;&#xff0c;即《安卓子系统》。他可…

【MATLAB】MVMD_ MFE_SVM_LSTM 神经网络时序预测算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 MVMD_MFE_SVM_LSTM神经网络时序预测算法结合了多变量多尺度分解&#xff08;MVMD&#xff09;、多尺度特征提取&#xff08;MFE&#xff09;、支持向量机&#xff08;SVM&#xff09;和长…

(vue)复合型输入框el-input输入数字类型,e,+,-等特殊符号可以输入

(vue)复合型输入框el-input输入数字类型&#xff0c;e&#xff0c;&#xff0c;-等特殊符号可以输入 效果 代码 <el-form-item label"分数区间"><el-inputplaceholder"请输入内容"v-model.number"formInline.scoreIntervalValue"clas…

DolphinScheduler——奇富科技的调度实践

目录 一、技术架构 二、业务挑战 2.1 调度任务量大 2.2 运维复杂 2.3 SLA要求高 三、调度优化实践 3.1 重复调度 3.2 漏调度 3.3 Worker服务卡死 3.4 任务重复运行 四、服务监控 4.1 方法耗时监控 4.2 任务调度链路监控 五、用户收益 原文大佬的这篇调度系统案例…

excel 实现分组排序功能

我们经常会遇到按照分组进行排序&#xff0c;在excel如何实现呢&#xff1f; 如下列的数据&#xff0c;需要按照分组&#xff0c;将得分从高到底排名 我们可以使用如下的公式操作即可实现 SUMPRODUCT((A$2:A$15A2)*(C$2:C$15>C2))1

解读人工智能的理论基石

1956年的一个夏天&#xff0c;在达特茅斯学院的一个小会议室里&#xff0c;一群充满好奇和野心的年轻科学家聚集在一起&#xff0c;他们有一个共同的梦想&#xff1a;创造能够模仿人类智能的机器。这不仅仅是科幻小说的情节&#xff0c;更是人工智能历史上一个真实的起点。从那…

2023 re:Invent 用 Amazon Q 打造你的知识库

前言 随着 ChatGPT 的问世&#xff0c;我们迎来了许多创新和变革的机会。一年一度的亚马逊云科技大会 re:Invent 也带来了许多前言的技术&#xff0c;其中 Amazon CEO Adam Selipsky 在 2023 re:Invent 大会中介绍 Amazon Q 让我印象深刻&#xff0c;这预示着生成式 AI 的又一…

ABAP 发送带EXCEL邮件

前言 没啥特殊需求&#xff0c;就是有个库龄报表用户想整邮件发送 实现 用的最简单的XLS文件作为excel附件发送出去 观察XLS文件的纯文本格式&#xff0c;每列之间用TAB制表符分隔&#xff0c;每行之间用回车符分隔 思路也比较明确&#xff0c;在SAP中实现这种格式&#xf…

React之组件定义和事件处理

一、组件的分类 在react中&#xff0c;组件分为函数组件和class组件&#xff0c;也就是无状态组件和有状态组件。 * 更过时候我们应该区别使用无状态组件&#xff0c;因为如果有状态组件会触发生命周期所对应的一些函数 * 一旦触发他生命周期的函数&#xff0c;它就会影响当前项…

微信小程序图片展示淡入淡出纯WXSS实现,无需使用消耗性能的动画引擎

进入下面小程序可以体验效果&#xff1a; 以下代码的淡入淡出是切换图片的时候动画效果显示的。需要用其他方式&#xff0c;可以基于这个wxss修改即可 原理就是&#xff0c;图片默认样式的opacity 是 0&#xff0c;通过变量改变样式的opacity即可&#xff0c;然后需要有transi…

苍穹外卖知识点总结(一)

简介 技术选型 展示项目中使用到的技术框架和中间件。 用户层&#xff1a;node.js Vue.js ElementUI 微信小程序 apache echarts 网关层&#xff1a;nginx 应用层&#xff1a;Spring Boot Spring MVC Spring Task httpclie…

IntelliJ IDEA 使用 spring Initializr 快速搭建 spring boot 项目遇到的坑

maven使用的是3.5.3 一、创建SpringBoot 二、项目创建成功&#xff0c;启动右键&#xff0c;没有run方法 三、在pom.xml上右键&#xff0c;将其添加为maven项目&#xff0c;然后发现Test模块报错 四、查看pom.xml文件&#xff0c;发现2.3.5Release版本变红&#xff0c;怀疑是版…

mac flutter 配置

下载Flutter Sdk 直接访问官网无法下载&#xff0c;需要访问中国镜像下载 Flutter SDK 归档列表 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter Start building Flutter Android apps on macOS - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 下载后解压…

androidapp的开发流程,王者笔记

昨天去面了一家公司&#xff0c;价值观有受到冲击。 面试官技术方面没的说&#xff0c;他可能是个完美主义的人&#xff0c;无论什么事情到了他那里好像都有解决的方案&#xff0c;我被说的无所适从&#xff0c;感觉他很厉害。 但我不能认可的是&#xff0c;面试官觉得加班是…

会计师人物百度百科词条如何创建?腾轩科技传媒分享创建技巧不容你错过!

随着社交网络的发展&#xff0c;人物在互联网上的影响力变得越来越大。随之而来的是大家都希望在网络上拥有自己的百度百科词条&#xff0c;让更多人了解自己的事业和成就。腾轩科技传媒将为大家介绍会计师人物百度百科词条如何创建&#xff1f;人物百度百科创建技巧不容你错过…

32单片机基础:GPIO输入

1.1按键控制LED 按键介绍&#xff1a; 两种方式&#xff0c;我们一般用下接的方式。 第一个图&#xff1a;注意点。当按键按下&#xff0c;PA0接地&#xff0c;被置为低电平&#xff0c; 但是一旦按键松手&#xff0c;PA0悬空&#xff0c;引脚电压不确定。所以无论怎么读引脚…

Qt程序设计-柱状温度计自定义控件实例

Qt程序设计-柱状温度计自定义控件实例 本文讲解Qt柱状温度计自定义控件实例。 效果演示 创建温度计类 #ifndef THERMOMETER_H #define THERMOMETER_H#include <QWidget> #include <QPainter> #include <QDebug> #include <QTimer> #include <QPr…

element ui富文本编辑器的使用(quill-editor)

引用组件 <el-form-item label"内容"><editor v-model"obj.activity_content" :min-height"192"/> </el-form-item> 组件封装 <template><div><el-upload:action"uploadUrl":before-upload"…

开发知识点-Python-conda

Python-conda https://conda.io/miniconda.html conda search python conda env list conda deactivate conda activate python11 conda 是一个流行的开源包管理系统&#xff0c;它支持多种 Python 版本。 使用 conda 来创建和管理不同的 Python 环境&#xff0c;并在这些环…
推荐文章