首页 > 其他分享 >autMan框架适配器的编写教程

autMan框架适配器的编写教程

时间:2024-10-25 12:46:54浏览次数:8  
标签:教程 适配器 autMan json params aut message id

首先要确定接入社交媒体的类型,例如:
QQ类型为qq,
QQ频道类型为qb,
微信类型为wx,
tg客户端类型为tg,
tg官方机器人类型为tb,
这里确定的社交媒体类型不要与内置类型冲突,尽量使用2个字母代指。以下以tt类型为例。

一、HTTP方式连接时的适配器插件编写

即:社交媒体可以设置消息回调地址并提供http api调用的接入方式
(1)autMan会创建一个http服务,用于接收社交媒体的回调消息,地址为:http://autMan地址:端口/媒体类型/receive,例如:http://127.0.0.1:8080/tt/receive,将此地址设置到社交媒体的回调地址里即可,autMan接收的社交媒体的所有消息及事件全部转发给适配器处理,autMan创建的http api仅用于中转。
(2)autMan还会创建一个ws服务,用于和适配器之间进行通信,地址为http://autMan地址:端口/媒体类型/adapter,例如:http://127.0.0.1:8080/tt/adapter
(3)适配器编写时,需要连接到autMan的ws服务地址,建立消息通路。然后等待社交媒体的消息,autMan通过http服务接收到社交媒体的消息时会立即通过ws通道将原始消息转发给适配器(注:适配器也可以启动自己的http api服务用于直接接收社交媒体的回调消息,不经过autMan中转)。适配器要对社交媒体的原始消息进行处理,处理成autMan数据格式(如下:)

	Event      string      `json:"event"`       //事件类型
	EventData  interface{} `json:"event_data"`  //事件数据
	GuildId    string      `json:"guild_id"`    //社交圈子id
	GuildName  string      `json:"guild_name"`  //社交圈子名称
	BotId      string      `json:"bot_id"`      //机器人id
	BotName    string      `json:"bot_name"`    //机器人名称
	ChatId    string `json:"chat_id"`    //群组id
	ChatName  string `json:"chat_name"`  //群组名称
	UserId    string `json:"user_id"`    //用户id
	UserName  string `json:"user_name"`  //用户名称
	ImType    string `json:"im_type"`    //im类型
	MessageId string `json:"message_id"` //消息id
	Content   string `json:"content"`    //消息内容

autMan经过处理后会发送响应数据到适配器

	AutAction string      `json:"aut_action"`
	AutEcho   string      `json:"aut_echo"`
	AutParams interface{} `json:"aut_params"`

适配器将响应数据翻译成社交媒体api要求的格式进行发送即可。

适配器发送回执也是上面的数据格式,比如发送消息成功后,回执autMan 已发送消息的ID,aut_params里直接写id

二、社交媒体为反向WS接入时的适配器插件编写

(1)autMan会创建一个ws服务,用于接收社交媒体的回调消息,地址为:http://autMan地址:端口/媒体类型/receive,例如:http://127.0.0.1:8080/tt/receive,将此地址设置到社交媒体的反向ws地址里即可,autMan接收的社交媒体的所有消息及事件全部转发给适配器处理,autMan创建的ws服务仅用于中转。
(2)autMan还会创建一个ws服务,用于和适配器之间进行通信,地址为http://autMan地址:端口/媒体类型/adapter,例如:http://127.0.0.1:8080/tt/adapter
(3)适配器编写时,需要连接到autMan的ws服务地址,建立消息通路。然后等待社交媒体的消息,autMan接收到社交媒体的消息时会立即通过ws通道将原始消息转发给适配器(注:适配器也可以启动自己的ws服务用于直接接收社交媒体的回调消息和写入响应消息,不经过autMan中转)。适配器要对社交媒体的原始消息进行处理,处理格式同上,autMan经过处理后会发送响应数据到适配器,适配器将响应数据翻译成社交媒体要求的格式后再次发送到autMan ws通道,autMan将会直接将响应消息直接转发社交媒体。如果适配器直接创建了与社交媒体的通信,可直接将响应数据发送到社交媒体。

三、社交媒体提交WS服务时的适配器插件编写

(1)autMan会创建一个ws连接,用于接收社交媒体的回调消息,设置tt数据桶里的url参数为ws连接地址,autMan接收的社交媒体的所有消息及事件全部转发给适配器处理,autMan创建的ws连接仅用于中转。
(2)autMan还会创建一个ws服务,用于和适配器之间进行通信,地址为http://autMan地址:端口/媒体类型/adapter,例如:http://127.0.0.1:8080/tt/adapter
(3)适配器编写时,需要连接到autMan的ws服务地址,建立消息通路。然后等待社交媒体的消息,autMan接收到社交媒体的消息时会立即通过ws通道将原始消息转发给适配器(注:适配器也可以自行连接到社交媒体的ws服务用于直接接收社交媒体的回调消息和写入响应消息,不经过autMan中转)。适配器要对社交媒体的原始消息进行处理,处理格式同上,autMan经过处理后会发送响应数据到适配器,适配器将响应数据翻译成社交媒体要求的格式后再次发送到autMan ws通道,autMan将会直接将响应消息直接转发社交媒体。如果适配器直接创建了与社交媒体的通信,可直接将响应数据发送到社交媒体。

四、示例适配器

下面是某qq框架正向ws接入autMan的适配器,命名为adapter_q1_ws.py,放到plugin/adapters下面即可

'''
@Name: ncqq正向ws接入autMan的适配器
@Author: hdbjlizhe
@Date: 2024-08-25
@FilePath: plugin/adapters/adapter_q1_ws.py
@Description: 启用ncqq的正向ws,下面主函数的url地址为ws://autMan地址:端口/q1/adapter
@Bugs: 适用于autMan版本>=3.0.2,
@Commands:启用命令:set q1 enable true,重启生效
'''
import json
import asyncio
import websockets

async def receive_aut_data(websocket_aut, websocket_im):
    async for message in websocket_aut:
        #print(f"Received: {message}",flush=True)
        # 处理接收到的字符串转为json格式对象
        try:
            message_json = json.loads(message)
        except json.JSONDecodeError as e:
            print(f"JSON解析错误: {message}",flush=True)
            continue
        # 判断消息类型
        if "aut_echo" in message_json:#通信控制消息
            if message_json["aut_action"]=="reply_message" or message_json["aut_action"]=="push_message":
                aut_echo=message_json["aut_echo"]
                reply_message = {
                    "action":"send_private_msg",
                    "echo":aut_echo,
                    "params":{
                        "user_id":int(message_json["aut_params"]["user_id"]),
                        "message":message_json['aut_params']['content']
                    },
                }
                if "chat_id" in message_json["aut_params"] and message_json["aut_params"]["chat_id"]!="":
                    reply_message["action"]="send_group_msg"
                    reply_message["params"]["group_id"]=int(message_json["aut_params"]["chat_id"]),
                #print(json.dumps(reply_message),flush=True) # 发送回执消息给机器人main
                await asyncio.wait_for(websocket_im.send(json.dumps(reply_message)),timeout=1)
            elif message_json["aut_action"]=="delete_message" and "aut_params" in message_json and "message_id" in message_json["aut_params"]:
                reply_message = {
                    "action":"delete_msg",
                    "params":{
                        "message_id":int(message_json["aut_params"]["message_id"])
                    },
                }
                #print(json.dumps(reply_message),flush=True) # 发送回执消息给机器人main
                await asyncio.wait_for(websocket_im.send(json.dumps(reply_message)),timeout=1)
            
async def receive_im_data(websocket_aut, websocket_im):
    async for message in websocket_im:
        #print(f"Received: {message}",flush=True)
        # 处理接收到的字符串转为json格式对象
        try:
            message_json = json.loads(message)
        except json.JSONDecodeError as e:
            print(f"JSON解析错误: {message}",flush=True)
            continue
        # 判断消息类型
        if "self_id"in message_json and "message" in message_json:#传过来的消息
            # 获取消息内容
            commsg={
                "bot_id":f"{message_json['self_id']}",
                "user_id":f"{message_json['sender']['user_id']}",
                "user_name":message_json["sender"]["nickname"],
                "im_type":"q1",
                "message_id":f"{message_json['message_id']}",
                "content":message_json["message"],
                "raw_message":message_json["raw_message"]
            }
            if message_json["message_type"] == "group":
                if message_json['group_id']==735467280:
                    continue
                commsg["chat_id"] = f"{message_json['group_id']}" 
            await asyncio.wait_for(websocket_aut.send(json.dumps(commsg)),timeout=1)
        elif "retcode" in message_json and "data" in message_json and "message_id" in message_json["data"]:#im回执消息
            reply_message={
                "aut_echo":message_json['echo'],
                "aut_params":f"{message_json['data']['message_id']}",
            }
            #print(json.dumps(reply_message),flush=True) # 发送回执消息给机器人main
            await asyncio.wait_for(websocket_aut.send(json.dumps(reply_message)),timeout=1)

async def main():
    # 与autMan的通信地址ws
    uri_aut = "ws://192.168.31.10:9999/q1/adapter"
    # 与im的通信地址ws
    uri_im = "ws://192.168.31.49:3001"
    async with websockets.connect(uri_aut) as websocket_aut , websockets.connect(uri_im) as websocket_im:
        # 创建任务
        aut_task = asyncio.create_task(receive_aut_data(websocket_aut,websocket_im))
        im_task = asyncio.create_task(receive_im_data(websocket_aut,websocket_im))
        # 等待任务完成(可以根据需要修改)
        await asyncio.gather(aut_task,im_task)

asyncio.run(main())

ncqq反向ws接入autMan的适配器

'''
@Name: ncqq反向ws接入autMan的适配器
@Author: hdbjlizhe
@Date: 2024-08-25
@FilePath: plugin/adapters/adapter_q2_wsr.py
@Description: ncqq的反向ws为ws://autMan地址:端口/q2/receive,下面主函数的url地址为ws://autMan地址:端口/q2/adapter
@Bugs: 适用于autMan版本>=3.0.2,存在websocket长文本传输不完整而卡住的问题。请有能力的同学帮忙解决。
@Commands:启用命令:set q2 enable true,重启生效
'''
import json
import asyncio
import websockets

async def receive_data(websocket):
    async for message in websocket:
        #print(f"Received: {message}",flush=True)
        # 处理接收到的字符串转为json格式对象
        try:
            message_json = json.loads(message)
        except json.JSONDecodeError as e:
            print(f"JSON解析错误: {message}",flush=True)
            continue
        # 判断消息类型
        if "self_id"in message_json and "message" in message_json:#传过来的消息
            # 获取消息内容
            commsg={
                "bot_id":f"{message_json['self_id']}",
                "user_id":f"{message_json['sender']['user_id']}",
                "user_name":message_json["sender"]["nickname"],
                "im_type":"q2",
                "message_id":f"{message_json['message_id']}",
                "content":message_json["message"],
                "raw_message":message_json["raw_message"]
            }
            if message_json["message_type"] == "group":
                if message_json['group_id']==735467280:
                    continue
                commsg["chat_id"] = f"{message_json['group_id']}" 
            await asyncio.wait_for(websocket.send(json.dumps(commsg)),timeout=1)
        elif "aut_echo" in message_json:#通信控制消息
            if message_json["aut_action"]=="reply_message" or message_json["aut_action"]=="push_message":
                aut_echo=message_json["aut_echo"]
                reply_message = {
                    "action":"send_private_msg",
                    "echo":aut_echo,
                    "params":{
                        "user_id":int(message_json["aut_params"]["user_id"]),
                        "message":message_json['aut_params']['content']
                    },
                }
                if "chat_id" in message_json["aut_params"] and message_json["aut_params"]["chat_id"]!="":
                    reply_message["action"]="send_group_msg"
                    reply_message["params"]["group_id"]=int(message_json["aut_params"]["chat_id"]),
                #print(json.dumps(reply_message),flush=True) # 发送回执消息给机器人main
                await asyncio.wait_for(websocket.send(json.dumps(reply_message)),timeout=1)
            elif message_json["aut_action"]=="delete_message" and "aut_params" in message_json and "message_id" in message_json["aut_params"]:
                reply_message = {
                    "action":"delete_msg",
                    "params":{
                        "message_id":int(message_json["aut_params"]["message_id"])
                    },
                }
                #print(json.dumps(reply_message),flush=True) # 发送回执消息给机器人main
                await asyncio.wait_for(websocket.send(json.dumps(reply_message)),timeout=1)
        elif "retcode" in message_json and "data" in message_json and "message_id" in message_json["data"]:#im回执消息
            reply_message={
                "aut_echo":message_json['echo'],
                "aut_params":f"{message_json['data']['message_id']}",
            }
            #print(json.dumps(reply_message),flush=True) # 发送回执消息给机器人main
            await asyncio.wait_for(websocket.send(json.dumps(reply_message)),timeout=1)
            

async def main():
    uri = "ws://192.168.31.10:9999/q2/adapter"
    async with websockets.connect(uri) as websocket:
        # 创建任务
        consumer_task = asyncio.create_task(receive_data(websocket))
        # 等待任务完成(可以根据需要修改)
        await asyncio.gather(consumer_task)

asyncio.run(main())

ncqq正向ws接入autMan的适配器,nodejs版本

/*
@Name: ncqq正向ws接入autMan的适配器,nodejs版本
@Author: hdbjlizhe
@Date: 2024-08-25
@FilePath: plugin/adapters/adapter_q3_ws.js
@Description: 启用ncqq的正向ws,下面主函数的url地址为ws://autMan地址:端口/qq/adapter
@Bugs: 适用于autMan版本>=3.0.2,
@Commands:启用命令:set q3 enable true,重启生效
*/
const WebSocket = require('ws');

function receiveAutData(websocketAut, websocketIm) {
    websocketAut.on('message', (message) => {
        console.log(`Received from autMan: ${message}`);
        try {
            const messageJson = JSON.parse(message);
            if ("aut_echo" in messageJson) {
                if (messageJson["aut_action"] === "reply_message" || messageJson["aut_action"] === "push_message") {
                    const autEcho = messageJson["aut_echo"];
                    const replyMessage = {
                        action: "send_private_msg",
                        echo: autEcho,
                        params: {
                            user_id: parseInt(messageJson["aut_params"]["user_id"]),
                            message: messageJson['aut_params']['content']
                        }
                    };
                    if ("chat_id" in messageJson["aut_params"] && messageJson["aut_params"]["chat_id"]!== "") {
                        replyMessage.action = "send_group_msg";
                        replyMessage.params.group_id = parseInt(messageJson["aut_params"]["chat_id"]);
                    }
                    websocketIm.send(JSON.stringify(replyMessage));
                } else if (messageJson["aut_action"] === "delete_message" && "aut_params" in messageJson && "message_id" in messageJson["aut_params"]) {
                    const replyMessage = {
                        action: "delete_msg",
                        params: {
                            message_id: parseInt(messageJson["aut_params"]["message_id"])
                        }
                    };
                    websocketIm.send(JSON.stringify(replyMessage));
                }
            }
        } catch (error) {
            console.log(`JSON parsing error from autMan: ${message}`);
        }
    });
}

function receiveImData(websocketAut, websocketIm) {
    websocketIm.on('message', (message) => {
        console.log(`Received from ncqq: ${message}`);
        try {
            const messageJson = JSON.parse(message);
            if ("self_id" in messageJson && "message" in messageJson) {
                const commsg = {
                    bot_id: messageJson['self_id'].toString(),
                    user_id: messageJson['sender']['user_id'].toString(),
                    user_name: messageJson["sender"]["nickname"],
                    im_type: "q3",
                    message_id: messageJson['message_id'].toString(),
                    content: messageJson["message"],
                    raw_message: messageJson["raw_message"]
                };
                if (messageJson["message_type"] === "group") {
                    if (messageJson['group_id']==735467280) {
                        return;
                    }
                    commsg["chat_id"] = messageJson['group_id'].toString();
                }
                websocketAut.send(JSON.stringify(commsg));
            } else if ("retcode" in messageJson && "data" in messageJson && "message_id" in messageJson["data"]) {
                const replyMessage = {
                    aut_echo: messageJson['echo'],
                    aut_params: messageJson['data']['message_id'].toString()
                };
                websocketAut.send(JSON.stringify(replyMessage));
            }
        } catch (error) {
            console.log(`JSON parsing error from ncqq: ${message}`);
        }
    });
}

function main() {
    const uriAut = "ws://192.168.31.10:9999/q3/adapter";
    const uriIm = "ws://192.168.31.49:3001";
    const websocketAut = new WebSocket(uriAut);
    const websocketIm = new WebSocket(uriIm);
    websocketAut.on('open', () => {
        console.log('Connected to autMan');
    });
    websocketIm.on('open', () => {
        console.log('Connected to ncqq');
    });
    receiveAutData(websocketAut, websocketIm);
    receiveImData(websocketAut, websocketIm);
}

main();

ncqq使用http接口接入autMan的适配器

'''
@Name: ncqq使用http接口接入autMan的适配器
@Author: hdbjlizhe
@Date: 2024-08-25
@FilePath: plugin/adapters/adapter_qq_ws.py
@Description: 启用ncqq的http接口服务,修改代码中im_http_api地址,设置ncqq的http回调地址为http://autMan地址:端口/q4/receive,下面主函数的url地址为ws://autMan地址:端口/q4/adapter
@Bugs: 适用于autMan版本>=3.0.2,
@Commands:启用命令:set q4 enable true,重启生效
'''
import aiohttp
import json
import asyncio
import websockets

# ncqq的http接口地址
im_http_api="http://192.168.31.49:3000"

async def receive_aut_data(websocket_aut):
    async for message in websocket_aut:
        #print(f"Received: {message}",flush=True)
        # 处理接收到的字符串转为json格式对象
        try:
            message_json = json.loads(message)
        except json.JSONDecodeError as e:
            print(f"JSON解析错误: {message}",flush=True)
            continue
        # 判断消息类型
        # 判断消息类型
        if "self_id"in message_json and "message" in message_json:#传过来的消息
            # 获取消息内容
            commsg={
                "bot_id":f"{message_json['self_id']}",
                "user_id":f"{message_json['sender']['user_id']}",
                "user_name":message_json["sender"]["nickname"],
                "im_type":"q4",
                "message_id":f"{message_json['message_id']}",
                "content":message_json["message"],
                "raw_message":message_json["raw_message"]
            }
            if message_json["message_type"] == "group":
                if message_json['group_id']==735467280:
                    continue
                commsg["chat_id"] = f"{message_json['group_id']}" 
            await asyncio.wait_for(websocket_aut.send(json.dumps(commsg)),timeout=1)
        elif "aut_echo" in message_json:#通信控制消息
            if message_json["aut_action"]=="reply_message" or message_json["aut_action"]=="push_message":
                aut_echo=message_json["aut_echo"]
                reply_message = {
                    "action":"/send_private_msg",
                    "params":{
                        "user_id":int(message_json["aut_params"]["user_id"]),
                        "message":message_json['aut_params']['content']
                    },
                }
                if "chat_id" in message_json["aut_params"] and message_json["aut_params"]["chat_id"]!="":
                    reply_message["action"]="/send_group_msg"
                    reply_message["params"]["group_id"]=int(message_json["aut_params"]["chat_id"]),
                #print(json.dumps(reply_message),flush=True) # 发送回执消息给机器人main
                message_id = await post_data(reply_message["action"],reply_message["params"])
                if message_id!=None:
                    reply_message={
                        "aut_echo":aut_echo,
                        "aut_params":f"{message_id}",
                    }
                    #print(json.dumps(reply_message),flush=True) # 发送回执消息给机器人main
                    await asyncio.wait_for(websocket_aut.send(json.dumps(reply_message)),timeout=1)
            elif message_json["aut_action"]=="delete_message" and "aut_params" in message_json and "message_id" in message_json["aut_params"]:
                reply_message = {
                    "action":"delete_msg",
                    "params":{
                        "message_id":int(message_json["aut_params"]["message_id"])
                    },
                }
                #print(json.dumps(reply_message),flush=True) # 发送回执消息给机器人main
                await post_data(reply_message["action"],reply_message["params"])
    
async def post_data(url, data):
  async with aiohttp.ClientSession() as session:
    async with session.post(im_http_api + url, json=data) as response:
      if response.status == 200:
        try:
          # Assuming JSON response with "messageid" field
          content = await response.json()
          message_id = content['data']['message_id']
          #print(f"Messageid: {message_id}", flush=True)
          return message_id
        except (aiohttp.client_exceptions.ContentTypeError, KeyError):
          # Handle non-JSON response or missing "messageid" field
          print(f"Error: Unexpected response format for {url}")
          return None
      else:
        print(f"POST {url} failed with status {response.status}", flush=True)
        return None  # Indicate error
            
        
async def main():
    # 与autMan的通信地址ws
    uri_aut = "ws://192.168.31.10:9999/q4/adapter"
    async with websockets.connect(uri_aut) as websocket_aut:
        # 创建任务
        aut_task = asyncio.create_task(receive_aut_data(websocket_aut))
        # 等待任务完成(可以根据需要修改)
        await asyncio.gather(aut_task)

asyncio.run(main())

标签:教程,适配器,autMan,json,params,aut,message,id
From: https://blog.csdn.net/sinat_36129516/article/details/143231398

相关文章

  • kali一句话木马实验——远程控制(保姆级教程,新手小白也可以操作)
    1.打开apache;在终端中使用管理员权限输入serviceapache2start注:这个是为了打开80端口;打开之后可以使用nmapIP扫描查看80端口是否开放输入虚拟机IP地址,可以在物理机或者虚拟机浏览器打开apache;2.输入ifconfig查看虚拟机IP;3.在桌面找到home,在里面FileSystem目录下找......
  • Premiere(PR)下载:附安装包+视频学习教程+安装步骤
    从事视频后期工作的小伙伴,对Premiere应该不会陌生。AdobePremiere常常简称为PR,是一款专业的视频编辑(剪辑)软件。不得不承认,它是广播、电影和在线内容创作者的首选工具之一。Premiere具有强大的剪辑、修剪、合成和特效功能,可帮助用户创建高质量的视频内容。目前最新已推出PRCC......
  • 24全网最全comfyui工作流保姆级教程来啦!comfyui工作流搭建看这一篇就够了!
    前言一、SD主流UIStableDiffusion(SD)因为其开源特性,有着较高的受欢迎程度,并且基于SD的开源社区及教程、插件等,都是所有工具里最多的。基于SD,有不同的操作界面,可以理解为一个工具的不同客户端。WebUI和ComfyUI是两种较为流行的操作界面选项1.WebUI:优点:界面友好,插件丰......
  • Spring Boot 集成 RabbitMQ 完整教程(含 Windows 安装 RabbitMQ)
    在现代分布式系统中,消息队列是一种非常重要的组件,用于解耦应用程序的各个部分、异步处理任务、提高系统的可扩展性和容错性。RabbitMQ是一种流行的消息队列中间件,支持多种消息协议,其中AMQP(AdvancedMessageQueuingProtocol)是其默认支持的协议。本文将详细介绍如何在Wi......
  • 2024年全新圈子论坛系统的全方位指南+保姆版搭建教程
    一、技术选型:根据需求分析的结果,选择合适的技术栈是搭建圈子论坛系统的关键。后端技术:可以选择Java、Python等后端开发语言和框架,以及MySQL、MongoDB等数据库类型,用于处理用户请求、存储数据等。前端技术:Vue、React、Angular等前端框架,以及uni-app等跨平台框架,可用于构建用户......
  • 帝国cms后台登录用户名账号密码忘记了怎么重置找回(帝国CMS后台登录账号密码重置教程)
    如果你忘记了帝国CMS的后台登录账号密码,可以通过以下步骤重置:1.登录phpMyAdmin控制界面打开浏览器,访问你的phpMyAdmin控制界面。输入数据库的账号和密码,登录到数据库管理界面。2.找到网站对应的数据库在phpMyAdmin中,找到你的网站对应的数据库。默认情况下,帝国CMS的用户......
  • 使用本地浏览器打开远程服务器生成的网页——详细教程
    使用本地浏览器打开远程服务器生成的网页——详细教程在日常开发或运维中,我们常常需要访问部署在远程服务器上的网页应用,例如JupyterNotebook、Web服务等。通过SSH端口转发,我们可以在不暴露远程服务器端口的情况下,使用本地浏览器直接访问远程服务器生成的网页。本文将......
  • 在 Windows Server 2008 R2 中,您可以使用批处理(.bat)文件来查询 Win32_NetworkAdapterC
    在WindowsServer2008R2中,Win32_NetworkAdapterConfiguration类是Windows管理工具(WMI)基础结构的一部分。它提供了有关服务器上网络适配器配置的详细信息。您可以使用此类查询各种网络设置,例如IP地址、子网掩码、DNS服务器和DHCP设置。Win32_NetworkAdapterConfigurat......
  • 通过 PowerShell 更换以太网适配器的 IPv6 DNS 服务器,可以使用 Set-DnsClientServerAd
    通过PowerShell更换以太网适配器的IPv6DNS服务器,可以使用Set-DnsClientServerAddresscmdlet来设置DNS服务器地址。以下是如何操作的详细步骤:步骤1:打开PowerShell以管理员身份运行PowerShell:右键单击开始菜单,选择 WindowsPowerShell(管理员)。步骤2:......
  • SketchUp:材质与纹理应用教程_2024-07-16_07-25-53.Tex
    SketchUp:材质与纹理应用教程SketchUp基础介绍SketchUp软件概述SketchUp,由Trimble公司开发,是一款广泛应用于建筑、室内设计、景观设计等领域的3D建模软件。它以其直观的用户界面和强大的建模功能而闻名,适合从初学者到专业人士的广泛用户群体。SketchUp分为两个版本:Ske......