C#的内网穿透学习(附源码)非常详细,零基础入门到精通,收藏这一篇就够了

C#代码实现TCP穿透(打洞) 内网之间实现TCP通讯需要用到内网穿透技术,具体原理网上都有,参考: https://blog.youkuaiyun.com/leisure512/article/details/4900191 https://blog.youkuaiyun.com/aaron133/article/details/79206257 TCP穿透成功的条件需要两边网络都是锥形NAT(或者至少一端网络是锥形NAT),具体可以参考 h... 阅读详情

如何让两台处在不同内网的主机直接互连?你需要内网穿透!

上图是一个非完整版内外网通讯图由内网端先发起,内网设备192.168.1.2:6677发送数据到外网时候必须经过nat会转换成对应的外网ip+端口,然后在发送给外网设备,外网设备回复数据也是发给你的外网ip+端口。

这只是单向的内去外,那反过来,如果外网的设备需要主动访问我局域网里的某一个设备是无法访问的,因为这个时候还没做nat转换所以外网不知道你内网设备的应用具体对应的是哪个端口,这个时候我们就需要内网穿透了,内网穿透也叫NAT穿透;

穿透原理

如上图所示经NAT转换后的内外网地址+端口,会缓存一段时间,在这段时间内192.168.1.2:6677和112.48.69.2020:8899的映射关系会一直存在,这样你的内网主机就得到一个外网地址,这个对应关系又根据NAT转换方法类型的不同,得用对应的方式实现打洞,NAT转换方法类型有下列几种(来源百度百科NAT):

**(1)Full cone NAT:**即著名的一对一(one-to-one)NAT。

一旦一个内部地址(iAddr:port1)映射到外部地址(eAddr:port2),所有发自iAddr:port1的包都经由eAddr:port2向外发送。任意外部主机都能通过给eAddr:port2发包到iAddr:port1(纯天然不用打洞!)

**(2)Address-Restricted cone NAT :**限制地址,即只接收曾经发送到对端的IP地址来的数据包。

一旦一个内部地址(iAddr:port1)映射到外部地址(eAddr:port2),所有发自iAddr:port1的包都经由eAddr:port2向外发送。

任意外部主机(hostAddr:any)都能通过给eAddr:port2发包到达iAddr:port1的前提是:iAddr:port1之前发送过包到hostAddr:any. "any"也就是说端口不受限制(只需知道某个转换后的外网ip+端口即可。)

**(3)Port-Restricted cone NAT:**类似受限制锥形NAT(Restricted cone NAT),但是还有端口限制。

一旦一个内部地址(iAddr:port1)映射到外部地址(eAddr:port2),所有发自iAddr:port1的包都经由eAddr:port2向外发送。一个外部主机(hostAddr:port3)能够发包到达iAddr:port1的前提是:iAddr:port1之前发送过包到hostAddr:port3.(双方需要各自知道对方转换后的外网ip+端口,然后一方先发一次尝试连接,另一方在次连接过来的时候就能直接连通了。)

(4)Symmetric NAT(对称NAT)

每一个来自相同内部IP与port的请求到一个特定目的地的IP地址和端口,映射到一个独特的外部来源的IP地址和端口。

同一个内部主机发出一个信息包到不同的目的端,不同的映射使用外部主机收到了一封包从一个内部主机可以送一封包回来(只能和Full cone NAT连,没法打洞,手机流量开热点就是,同一个本地端口连接不同的服务器得到的外网第地址和IP不同!)

例子:

下面用一个例子演示下“受限制锥形NAT”的打洞,实现了这个它前面两个类型也能通用。对称型的话不考虑,打不了洞。

我们知道要实现两台“受限制锥形NAT”互连重点就是要知道对方转换后的外网IP+端口,这样我们可以:

1、准备一台Full cone NAT 类型的外网服务端,接受来自两个客户端的连接,并对应告知对方ip+端口;

2、知道了对方ip+端口 需要设置socke:Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);这样才能端口复用;目的就是让连接对外的端口一致;

3、最后,我们可以让两台客户端互相连接,或者一台先发一个请求,打个洞;另一个在去连接;

代码:

1、TCP+IOCP方式,相对 “面向对象”地实现穿透!

服务端 ServerListener类,用SocketAsyncEventArgs:

/// <summary>  
/// 打洞服务端,非常的简单,接收两个连接并且转发给对方;  
/// </summary>  
public class ServerListener : IServerListener  
{  
    IPEndPoint EndPoint { get; set; }  
    //消息委托  
    public delegate void EventMsg(object sender, string e);  
    public static object obj = new object();  
    //通知消息  
    public event EventMsg NoticeMsg;  
    //接收事件  
    public event EventMsg ReceivedMsg;  
    /// <summary>  
    /// 上次链接的  
    /// </summary>  
    private Socket Previous;  
    public ServerListener(IPEndPoint endpoint)    {  
        this.EndPoint = endpoint;  
    }  
    private Socket listener;  
    public void Start()    {  
        this.listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  
        var connectArgs = new SocketAsyncEventArgs();              
        listener.Bind(EndPoint);  
        listener.Listen(2);  
        EndPoint = (IPEndPoint)listener.LocalEndPoint;   
        connectArgs.Completed += OnAccept;  
        //是否同步就完成了,同步完成需要自己触发  
        if (!listener.AcceptAsync(connectArgs))  
            OnAccept(listener, connectArgs);  
    }  
    byte[] bytes = new byte[400];  
    private void OnAccept(object sender, SocketAsyncEventArgs e)    {  
        Socket socket = null;  
        try  
        {  
            var remoteEndPoint1 = e.AcceptSocket.RemoteEndPoint.ToString();  
            NoticeMsg?.Invoke(sender, $"客户端:{remoteEndPoint1}连接上我了!\r\n");  
            SocketAsyncEventArgs readEventArgs = new SocketAsyncEventArgs();  
            readEventArgs.Completed += OnSocketReceived;  
            readEventArgs.UserToken = e.AcceptSocket;  
            readEventArgs.SetBuffer(bytes, 0, 400);  
            if (!e.AcceptSocket.ReceiveAsync(readEventArgs))  
                OnSocketReceived(e.AcceptSocket, readEventArgs);  
            lock (obj)  
            {  
                socket = e.AcceptSocket;  
                //上次有链接并且链接还”健在“  
                if (Previous == null||! Previous.Connected)  
                {  
                    Previous = e.AcceptSocket;  
                }  
                else  
                {  
                    //Previous.SendAsync()..?  
                    Previous.Send(Encoding.UTF8.GetBytes(remoteEndPoint1 + "_1"));  
                    socket.Send(Encoding.UTF8.GetBytes(Previous.RemoteEndPoint.ToString() + "_2"));  
                    NoticeMsg?.Invoke(sender, $"已经通知双方!\r\n");  
                    Previous = null;  
                }  
            }   
            e.AcceptSocket = null;  
            if (e.SocketError != SocketError.Success)  
                throw new SocketException((int)e.SocketError);  
             
            if(!listener.AcceptAsync(e))  
                OnAccept(listener, e);  
        }  
        catch  
        {  
            socket?.Close();  
       }  
    }  
    public void Close()    {  
        using (listener)  
        {  
           // listener.Shutdown(SocketShutdown.Both);  
            listener.Close();  
        }  
        //throw new NotImplementedException();  
    }  
    /// <summary>  
    /// 此处留有一个小BUG,接收的字符串大于400的时候会有问题;可以参考客户端修改  
    /// </summary>  
    public void OnSocketReceived(object sender, SocketAsyncEventArgs e)    {             
        Socket socket = e.UserToken as Socket;              
        var remoteEndPoint = socket.RemoteEndPoint.ToString();  
        try  
        {   
            if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)  
  
            {  
                ReceivedMsg?.Invoke(sender, $"收到:{remoteEndPoint}发来信息:{Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred)}\r\n");                   
  
            }  
            else  
            {  
                socket?.Close();  
                NoticeMsg?.Invoke(sender, $"链接:{remoteEndPoint}释放啦!\r\n");  
                return;  
            }  
            if (!socket.ReceiveAsync(e))  
                OnSocketReceived(socket, e);  
        }  
        catch  
        {  
            socket?.Close();  
        }  
        //{  
        //   if (!((Socket)sender).AcceptAsync(e))  
        //        OnSocketReceived(sender, e);  
        //}  
        //catch  
        //{  
        //    return;  
        //}  
    }  
}

2、客户端类 PeerClient用BeginReceive和EndReceive实现异步;

public class StateObject  
{  
    public Socket workSocket = null;  
    public const int BufferSize = 100;  
    public byte[] buffer = new byte[BufferSize];  
    public List<byte> buffers = new List<byte>();  
    //是不是和服务器的链接  
    public bool IsServerCon = false;  
}  
/// <summary>  
/// 打洞节点客户端 实现的功能:  
/// 连接服务器获取对方节点ip   
/// 请求对方ip(打洞)  
/// 根据条件判断是监听连接还是监听等待连接  
/// </summary>  
public class PeerClient : IPeerClient  
{  
    //ManualResetEvent xxxxDone =  new ManualResetEvent(false);  
    //Semaphore   
    /// <summary>  
    /// 当前链接  
    /// </summary>  
    public Socket Client { get;private set; }  
    #region 服务端  
    public string ServerHostName { get;private set; }  
    public int ServerPort { get; private set; }  
    #endregion  
  
    #region 接收和通知事件  
    public delegate void EventMsg(object sender, string e);  
    //接收事件  
    public event EventMsg ReceivedMsg;  
    //通知消息  
    public event EventMsg NoticeMsg;  
    #endregion  
    //本地绑定的节点  
    private IPEndPoint LocalEP;  
    public PeerClient(string hostname, int port)    {  
        Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  
        this.ServerHostName = hostname;  
        this.ServerPort = port;  
    }  
  
    /// <summary>  
    /// 初始化客户端(包括启动)  
    /// </summary>  
    public void Init()    {  
        try  
        {  
            Client.Connect(ServerHostName, ServerPort);  
        }  
        catch (SocketException ex)  
        {  
            NoticeMsg?.Invoke(Client, $"连接服务器失败!{ex}!\r\n");  
            throw;  
        }  
        catch (Exception ex)  
        {  
            NoticeMsg?.Invoke(Client, $"连接服务器失败!{ex}!\r\n");  
            throw;  
        }  
        NoticeMsg?.Invoke(Client, $"连接上服务器了!\r\n");  
        var _localEndPoint = Client.LocalEndPoint.ToString();  
        LocalEP = new IPEndPoint(IPAddress.Parse(_localEndPoint.Split(':')[0])  
            , int.Parse(_localEndPoint.Split(':')[1]));  
        Receive(Client);  
    }  
    private void Receive(Socket client)    {  
        try  
        {  
            StateObject state = new StateObject();  
            state.workSocket = client;  
            state.IsServerCon = true;  
            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,  
                new AsyncCallback(ReceiveCallback), state);  
        }  
        catch (Exception e)  
        {  
            NoticeMsg?.Invoke(Client, $"接收消息出错了{e}!\r\n");  
        }  
    }  
    private void ReceiveCallback(IAsyncResult ar)    {  
        try  
        {  
            var state = (StateObject)ar.AsyncState;  
            Socket _client = state.workSocket;  
            //因为到这边的经常Connected 还是true  
            //if (!_client.Connected)  
            //{  
            //    _client.Close();  
            //    return;  
            //}  
            SocketError error = SocketError.Success;  
            int bytesRead = _client.EndReceive(ar,out error);  
            if (error == SocketError.ConnectionReset)  
            {  
                NoticeMsg?.Invoke(Client, $"链接已经释放!\r\n");  
                _client.Close();  
                _client.Dispose();  
                return;  
            }  
            if (SocketError.Success!= error)  
            {  
               throw new SocketException((int)error);  
            }  
            var arr = state.buffer.AsQueryable().Take(bytesRead).ToArray();  
            state.buffers.AddRange(arr);  
            if (bytesRead >= state.buffer.Length)  
            {  
                _client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,  
                  new AsyncCallback(ReceiveCallback), state);  
                ////state.buffers.CopyTo(state.buffers.Count, state.buffer, 0, bytesRead);  
                //_client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,  
                //    new AsyncCallback(ReceiveCallback), state);  
            }  
            else  
            {  
                var _msg = Encoding.UTF8.GetString(state.buffers.ToArray());  
                ReceivedMsg?.Invoke(_client, _msg);  
                if (state.IsServerCon)  
                {  
                    _client.Shutdown(SocketShutdown.Both);  
                    _client.Close();  
                    int retryCon = _msg.Contains("_1") ? 1 : 100;  
                    _msg = _msg.Replace("_1", "").Replace("_2", "");  
                    TryConnection(_msg.Split(':')[0], int.Parse(_msg.Split(':')[1]), retryCon);  
                    return;  
                }  
                state = new StateObject();  
                state.IsServerCon = false;  
                state.workSocket = _client;  
                _client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,  
                 new AsyncCallback(ReceiveCallback), state);  
            }  
        }               
        catch (SocketException ex)  
        {  
            //10054  
            NoticeMsg?.Invoke(Client, $"链接已经释放!{ex}!\r\n");  
        }  
        catch (Exception e)  
        {  
            NoticeMsg?.Invoke(Client, $"接收消息出错了2{e}!\r\n");  
        }  
    }  
    /// <summary>  
    /// 打洞或者尝试链接  
    /// </summary>  
    private void TryConnection(string remoteHostname, int remotePort,int retryCon)    {  
        Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  
        Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);  
        var _iPRemotePoint = new IPEndPoint(IPAddress.Parse(remoteHostname), remotePort);  
        Client.Bind(LocalEP);  
        System.Threading.Thread.Sleep(retryCon==1?1:3*1000);  
        for (int i = 0; i < retryCon; i++)  
        {  
            try  
            {  
                Client.Connect(_iPRemotePoint);  
                NoticeMsg?.Invoke(Client, $"已经连接上:{remoteHostname}:{remotePort}!\r\n");  
                StateObject state = new StateObject();  
                state.workSocket = Client;  
                state.IsServerCon = false;  
                Client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,  
                 new AsyncCallback(ReceiveCallback), state);  
                return;  
            }  
            catch  
            {  
                NoticeMsg?.Invoke(Client, $"尝试第{i+1}次链接:{remoteHostname}:{remotePort}!\r\n");  
            }  
        }  
        if (retryCon==1)  
        {  
            Listening(LocalEP.Port);  
            return;  
        }  
        NoticeMsg?.Invoke(Client, $"尝试了{retryCon}次都没有办法连接到:{remoteHostname}:{remotePort},凉了!\r\n");   }  
  
    /// <summary>  
    /// 如果连接不成功,因为事先有打洞过了,根据条件监听 等待对方连接来  
    /// </summary>  
    private void Listening(int Port)    {  
        try  
        {  
            Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  
            Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);  
            Client.Bind(new IPEndPoint(IPAddress.Any, Port));Client.Listen((int)SocketOptionName.MaxConnections);  
            NoticeMsg?.Invoke(Client, $"开始侦听断开等待链接过来!\r\n");  
            StateObject state = new StateObject();  
            state.IsServerCon = false;  
            var _socket = Client.Accept();//只有一个链接 不用BeginAccept  
            Client.Close();//关系现有侦听  
            Client = _socket;  
            state.workSocket = Client;  
            NoticeMsg?.Invoke(Client, $"接收到来自{Client.RemoteEndPoint}的连接!\r\n");  
            Client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,  
                new AsyncCallback(ReceiveCallback), state);  
        }  
        catch (Exception ex)  
        {  
            NoticeMsg?.Invoke(Client, $"监听出错了{ex}凉了!\r\n");  
        }  
        //scoket.send  
    }  
    /// <summary>  
    /// 本例子只存在一个成功的链接,对成功的连接发送消息!  
    /// </summary>  
    /// <param name="strMsg"></param>  
    public void Send(string strMsg)    {   
        byte[] bytes = Encoding.UTF8.GetBytes(strMsg);   
        Client.BeginSend(bytes, 0, bytes.Length, 0,  
            new AsyncCallback(SendCallback), Client);  
    }  
    private void SendCallback(IAsyncResult ar)    {  
        try  
        {   
            Socket _socket = (Socket)ar.AsyncState;  
            //if(ar.IsCompleted)  
            _socket.EndSend(ar);   
        }  
        catch (Exception e)  
        {  
            NoticeMsg?.Invoke(Client, $"发送消息出错了{e}!\r\n");  
        }  
    }  
}

**完整代码:**https://gitee.com/qqljcn/zsg_-peer-to-peer

二、面向过程方式

Task+(TcpClient+TcpListener )|(UdpClient)实现 tcp|udp的打洞!这个就不贴代码了直接放码云连接

https://gitee.com/qqljcn/zsg_-peer-to-peer_-lite

三、说明

1、本人是个老菜鸟代码仅供参考,都是挺久以前写的也没有经过严格的测试仅能演示这个例子,有不成熟的地方,烦请各位大神海涵指教;

2、不要都用本机试这个例子,本机不走nat

3、然后udp因为是无连接的所以打孔成功后不要等太久再发消息,nat缓存一过就失效了!

4、确定自己不是对称型nat的话,如果打洞不成功,那就多试几次!

5 、我这个例子代码名字叫 PeerToPeer 但不是真的p2p, 微软提供了p2p的实现 在using System.Net.PeerToPeer命名空间下。

以上是通过nat的方式,另外还有一种方式是,通过一个有外网ip的第三方服务器转发像 花生壳、nat123这类软件,也有做个小程序,并且自己在用以后演示;

- EOF -

为了帮助大家更好的学习网络安全,我给大家准备了一份网络安全入门/进阶学习资料,里面的内容都是适合零基础小白的笔记和资料,不懂编程也能听懂、看懂这些资料!

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

[2024最新优快云大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享]


在这里插入图片描述

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

[2024最新优快云大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享]
在这里插入图片描述

在这里插入图片描述

C#实现内网穿透的源代码 PushMsg("{remoteEndPoint1}连接上我了!PushMsg("{remoteEndPoint2}连接上我了!PushMsg("{remoteEndPoint2}转发出去了!PushMsg("{remoteEndPoint1}转发出去了!PushMsg("继续等待下一轮!PushMsg("启动侦听!C#实现内网穿透的源代码。 阅读详情

相关推荐

【计算机网络通信】计算机之间的局域网通信和互联网通信方法(附Python和C#代码)

本文介绍了局域网通信和互联网通信的python和c#实现方法。

qq_44951699的博客 2506

c# Socket开发内网穿透配置服务器

内网穿透, 内网穿透访问服务器,c#开发服务器,Socket套接字发开

qq_32470423的博客 1191

C#实现内网穿透(附完整源码)

C#实现内网穿透(附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 929

C#的内网穿透学习(附源码)非常详细,零基础入门到精通,收藏这一篇就够了_c# socket

C#的内网穿透学习(附源码)非常详细,零基础入门到精通,收藏这一篇就够了_c# socket

喜欢Python编程的程序员柚柚呀 794

太强了,使用 C# 开发的开源内网穿透工具

🏆作者:科技、互联网行业优质创作者🏆专注领域:.Net技术、软件架构、人工智能、数字化转型、DeveloperSharp、微服务、工业互联网、智能制造🏆欢迎关注我(),里面有很多技术文章,,能助你快速成长。升职+涨薪!!NSmartProxNSmartProxy是一款强大开源的内网穿透工具,采用.NET Core的全异步模式打造。

.Net技术、软件架构、人工智能、数字化转型、DeveloperSharp、微服务、工业互联网、智能制造 1177

C# Socket实战源码

类IPEndPoint 是抽象类EndPoint的实现类 Socket对象的RemoteEndPoint、LocalEndPoint都是这个类型 属性Address:使用IPv4表示的地址 属性Port:使用int表示的端口 类Socket 这个类既可以用于服务器端的开发,也可以用于客户端的开发; 构造方法: 参数AddressFamily:指定使用IPv4的地址InterNetwork; 参数SocketType:指定使用流式传输Stream; 参数ProtocolType:指定协议类型Tc

汽车电子软件领域知识分享 1508

**C#的内网穿透学习(附源码)非常详细,零基础入门到精通,收藏这一篇就够了**

如何让两台处在不同内网的主机直接互连?你需要内网穿透!上图是一个非完整版内外网通讯图由内网端先发起,内网设备192.168.1.2:6677发送数据到外网时候必须经过nat会转换成对应的外网ip+端口,然后在发送给外网设备,外网设备回复数据也是发给你的外网ip+端口。这只是单向的内去外,那反过来,如果外网的设备需要主动访问我局域网里的某一个设备是无法访问的,因为这个时候还没做nat转换所以外网不知道你内网设备的应用具体对应的是哪个端口,这个时候我们就需要内网穿透了,内网穿透也叫NAT穿透;

QIANDXX的博客 1124

一个使用C#实现的内网穿透工具,可实现内网服务挂载在公网

一个使用C#实现的内网穿透工具,可实现内网服务挂载在公网

【2025详细版】C#的内网穿透学习(附源码),从零基础到进阶,收藏这篇就够了

一个外部主机(hostAddr:port3)能够发包到达iAddr:port1的前提是:iAddr:port1之前发送过包到hostAddr:port3.(双方需要各自知道对方转换后的外网ip+端口,然后一方先发一次尝试连接,另一方在次连接过来的时候就能直接连通了。这只是单向的内去外,那反过来,如果外网的设备需要主动访问我局域网里的某一个设备是无法访问的,因为这个时候还没做nat转换所以外网不知道你内网设备的应用具体对应的是哪个端口,这个时候我们就需要内网穿透了,内网穿透也叫NAT穿透;

Button12138的博客 1111

Silly Tavern(酒馆)AI 角色扮演下载与安装教程(Windows本地部署)

SillyTavern是一款开源AI角色扮演前端工具,支持沉浸式对话和长期角色互动。本文详细介绍了在Windows系统F盘部署SillyTavern的完整流程,包括下载项目、安装Node.js和Git环境、配置路径、启动服务等关键步骤,并特别说明非系统盘路径可能遇到的npm安装问题及解决方法。成功启动后,用户可通过浏览器访问本地地址使用该工具进行AI角色扮演互动。

Tan3851的博客 1万+

RDD2022 数据格式转换与清洗

Rdd2022数据集,是关于道路损伤的数据集,与rdd2020相比增加了两万多张图片但是由于格式不能被yolo直接使用且其中有大量的图片没有符合要求的标注,特写此文章记录数据清洗与格式化的过程。

蓝胖子的博客 9952

NSmartProxy:一款.NET开源、跨平台的内网穿透工具

思维导航前言内网穿透工具介绍特点与优势运行原理项目源代码服务端运行效果项目源码地址优秀项目和框架精选 前言 今天大姚给大家分享一款.NET开源、免费(MIT License)、跨平台的内网穿透工具,采用.NET Core的全异步模式打造:NSmartProxy。 内网穿透工具介绍 内网穿透工具是一种能够允许用户从互联网上的任何地方安全地访问并管理处于内网(如家庭网络、公司局域网等)中的设备的工具。...

weixin_42089607的博客 293

给麒麟KylinOS服务器加把锁:手把手配置符合等保要求的密码强度策略

本文详细介绍了如何在麒麟KylinOS服务器上配置符合等保要求的密码强度策略,包括pwquality.conf和login.defs的核心参数设置、等保合规的进阶配置技巧以及企业环境中的平衡艺术。通过实战案例和测试方法,帮助管理员构建坚固的密码防线,确保系统安全。

weixin_33749242的博客 419

使用.NetCore开发的内网穿透工具

开篇引言一款强大开源的内网穿透工具-NSmartProxy,采用.NET CORE的全异步模式打造。???? 产品亮点速递????跨平台无忧兼容性强NSmartProxy采用前沿技术,无论是MacOS的优雅、Linux的灵活,还是Windows的普及,它都能完美适配,让你的内网穿透之旅畅通无阻。????使用简便,配置秒懂告别复杂的设置流程,NSmartProxy以用户友好为核心,一键安装,几步配置,即可开启...

dotNET跨平台 384

【UVM实战】第一章:配置UVM环境(以VCS为例),跑通书上的例子(包括清理中间文件方法、使用DVE查看波形方法、命令执行原理探究)

如何配置UVM的VCS运行环境,运行书本上的例子呢?本节将会为你详细解答!

悟已往之不谏 知来者之可追 8137

倾斜摄影数据转换为3DTile格式的方法:基于CesiumLab GIS

通过使用CesiumLab GIS,倾斜摄影数据可以方便地转换为3DTile格式,并在CesiumJS等3D地理信息可视化工具中进行展示和分析。一旦成功导入3DTile数据,就可以在CesiumLab GIS中利用其强大的可视化和分析功能进行进一步的处理。转换完成后,可以将生成的3DTile数据导入到CesiumLab GIS中进行可视化和分析。启动CesiumLab GIS应用程序,并按照界面上的指导导入转换后的3DTile数据。脚本将开始执行,并将倾斜摄影数据转换为3DTile格式。

ObDjango的博客 1076

一个基于 .NET 开源免费的异地组网和内网穿透工具

该项目已收录到C#/.NET/.NET Core优秀项目和框架精选中,关注优秀项目和框架精选能让你及时了解C#、.NET和.NET Core领域的最新动态和最佳实践,提高开发工作效率和质量。linker是一个基于 .NET8 开源免费(GPL-2.0 license)的异地组网和内网穿透工具,支持TCP(支持IPV6)打洞、UDP打洞,服务器中继,异地组网使用虚拟网卡将各个客户端组建为局域网络、支持点对点、点对网、网对网等。更多项目实用功能和特性欢迎前往项目开源地址查看👀,别忘了给项目一个Star支持💖

weixin_33093437的博客 143

SOMEIP协议--第三节[SOMEIP/SD](SD格式)

Entry和Option是SD报文中最重要的内容,是服务发现功能的承载。7.Minor Version是指当前服务的小版本号,可以配置,用于给用户区分当前服务的版本用的。注意:stop offer,stop subscribe,Subscribe Nack 这三条的TTL一定设为0,唯一和offer,subscribe,Subscribe的区别。Option用来辅助Entry实现其功能,是Entry携带的附加信息,作用上一般是用来告诉对端自己业务的ip和port信息,方便对端通过ip和port发送报文。

qq_41816308的博客 1339
上一篇: LeetCode的基础入门(非常详细)零基础入门到精通,收藏这一篇就够了
下一篇: 程序员如何快速学习AI大模型应用工程开发,从后端转行为AI工程师(非常详细)从零基础到精通,收藏这篇就够了!
程序员_大白
博客等级 码龄5年 1万+粉丝 4001原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值