常驻后台的数据导出服务/常驻后台的数据导出服务.csproj
| <Project Sdk="Microsoft.NET.Sdk.Web"> |
| |
| <PropertyGroup> |
| <TargetFramework>net7.0</TargetFramework> |
| <Nullable>enable</Nullable> |
| <ImplicitUsings>enable</ImplicitUsings> |
| </PropertyGroup> |
| |
| <ItemGroup> |
| <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.0" /> |
| <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.0"> |
| <PrivateAssets>all</PrivateAssets> |
| <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
| </PackageReference> |
| <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" /> |
| <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.0" /> |
| <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.0" /> |
| <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> |
| |
| <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" /> |
| </ItemGroup> |
| |
| <ItemGroup> |
| <Content Update="appsettings.Development.json"> |
| <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |
| <ExcludeFromSingleFile>true</ExcludeFromSingleFile> |
| <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> |
| </Content> |
| <Content Update="appsettings.json"> |
| <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |
| <ExcludeFromSingleFile>true</ExcludeFromSingleFile> |
| <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> |
| </Content> |
| </ItemGroup> |
| |
| </Project> |
| |
常驻后台的数据导出服务/SeerSocket.cs
| using System.Net; |
| using System.Net.Sockets; |
| using System.Runtime.InteropServices; |
| |
| namespace Seer.SeerSocket; |
| public struct SeerMessageHead |
| { |
| public byte sync; |
| public byte version; |
| public ushort number; |
| public uint length; |
| public ushort type; |
| |
| #pragma warning disable 0414 //禁用警告 |
| #pragma warning disable 0169 //禁用警告 |
| private readonly byte ref0; |
| private readonly byte ref1; |
| private readonly byte ref2; |
| private readonly byte ref3; |
| private readonly byte ref4; |
| private readonly byte ref5; |
| #pragma warning restore 0414 //恢复警告 |
| #pragma warning restore 0169 //恢复警告 |
| |
| |
| public SeerMessageHead() |
| { |
| this.sync = 0x5A; |
| this.version = 0x01; |
| this.number = 0x0001; |
| } |
| public SeerMessageHead(ushort type) |
| { |
| this.type = type; |
| } |
| |
| |
| |
| |
| |
| public readonly byte[] ToBytes() |
| { |
| |
| int size = Marshal.SizeOf(this); |
| byte[] bytes = new byte[size]; |
| |
| IntPtr ptr = Marshal.AllocHGlobal(size); |
| Marshal.StructureToPtr(this, ptr, true); |
| Marshal.Copy(ptr, bytes, 0, size); |
| Marshal.FreeHGlobal(ptr); |
| |
| if (BitConverter.IsLittleEndian) |
| { |
| Array.Reverse(bytes, 2, 2); |
| Array.Reverse(bytes, 4, 4); |
| Array.Reverse(bytes, 8, 2); |
| } |
| return bytes; |
| |
| } |
| |
| |
| }; |
| |
| |
| |
| public class SeerSocket |
| { |
| public string ipAddress; |
| private readonly Dictionary<int, TcpClient> clients; |
| |
| public SeerSocket(string ipAddress, bool onlyRead = true) |
| { |
| this.ipAddress = ipAddress; |
| this.clients = new Dictionary<int, TcpClient> |
| { |
| { 19204, new TcpClient(this.ipAddress, 19204) } |
| }; |
| if (onlyRead) return; |
| this.clients.Add(19205, new TcpClient(this.ipAddress, 19205)); |
| this.clients.Add(19206, new TcpClient(this.ipAddress, 19206)); |
| this.clients.Add(19207, new TcpClient(this.ipAddress, 19207)); |
| this.clients.Add(19210, new TcpClient(this.ipAddress, 19210)); |
| |
| } |
| |
| |
| private TcpClient GetClient(int port) |
| { |
| return clients[port]; |
| } |
| |
| |
| public string Send(ushort type, string msg = "", int port = 19204) |
| { |
| var msgBody = NormalStrToHexByte(msg); |
| var msgHead = CreateMsgHead(type, (uint)msgBody.Length); |
| var response = this.SendRaw(msgHead, msgBody, port); |
| return response; |
| } |
| |
| private string SendRaw(byte[] msgHead, byte[] msgBody, int port) |
| { |
| try |
| { |
| TcpClient client = this.GetClient(port); |
| if (!client.Connected) |
| { |
| this.clients[port] = new TcpClient(ipAddress, port); |
| Console.WriteLine($"{ipAddress}:{port}:断开连接"); |
| return "fail"; |
| } |
| |
| NetworkStream serverStream = client.GetStream(); |
| serverStream.Write(msgHead, 0, msgHead.Length); |
| serverStream.Write(msgBody, 0, msgBody.Length); |
| serverStream.Flush(); |
| |
| byte[] inStream = new byte[16]; |
| while (16 != serverStream.Read(inStream, 0, 16)) |
| { |
| Thread.Sleep(20); |
| } |
| var recv_head = BytesToStructure<SeerMessageHead>(inStream); |
| byte[] recvbyte = BitConverter.GetBytes(recv_head.length); |
| Array.Reverse(recvbyte); |
| |
| var dsize = BitConverter.ToUInt32(recvbyte, 0); |
| const int bufferSize = 512; |
| List<byte> datalist = new List<byte>(); |
| int count = 0; |
| while (true) |
| { |
| byte[] buffer = new byte[bufferSize]; |
| int readSize = serverStream.Read(buffer, 0, bufferSize); |
| count += readSize; |
| datalist.AddRange(buffer); |
| if (count == dsize) |
| { |
| break; |
| } |
| } |
| |
| |
| string resMsg = System.Text.Encoding.UTF8.GetString(datalist.ToArray()); |
| return resMsg; |
| } |
| catch (SocketException) |
| { |
| return "fail"; |
| } |
| catch (IOException) |
| { |
| return "fail"; |
| } |
| } |
| |
| public void CloseAll() |
| { |
| foreach (var client in this.clients.Values) |
| { |
| client.Close(); |
| } |
| } |
| |
| private T BytesToStructure<T>(byte[] bytesBuffer) |
| { |
| if (bytesBuffer.Length < Marshal.SizeOf(typeof(T))) |
| { |
| throw new ArgumentException("size error"); |
| } |
| |
| nint bufferHandler = Marshal.AllocHGlobal(bytesBuffer.Length); |
| |
| for (int index = 0; index < bytesBuffer.Length; index++) |
| { |
| Marshal.WriteByte(bufferHandler, index, bytesBuffer[index]); |
| } |
| |
| |
| T? structObject = Marshal.PtrToStructure<T>(bufferHandler); |
| |
| Marshal.FreeHGlobal(bufferHandler); |
| |
| if (structObject == null) |
| { |
| throw new InvalidOperationException("Failed to convert bytes to structure."); |
| } |
| |
| return structObject!; |
| } |
| |
| private byte[] NormalStrToHexByte(string str) |
| { |
| byte[] result = new byte[str.Length]; |
| |
| byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str); |
| |
| for (int i = 0; i < buffer.Length; i++) |
| { |
| result[i] = Convert.ToByte(buffer[i].ToString("X2"), 16); |
| } |
| return result; |
| } |
| |
| private byte[] CreateMsgHead(ushort type, uint msgLen) |
| { |
| var msgHead = new SeerMessageHead |
| { |
| type = type, |
| length = msgLen |
| }; |
| return msgHead.ToBytes(); |
| } |
| |
| public static void PrintBytes(byte[] bytes) |
| { |
| foreach (byte b in bytes) |
| { |
| Console.Write("{0:X2} ", b); |
| } |
| |
| } |
| |
| |
| |
| |
| |
| } |
| |
| |
| |
常驻后台的数据导出服务/ExplortStatisticBgService.cs
| using System.Text; |
| using System.Text.Json; |
| using Newtonsoft.Json; |
| using Newtonsoft.Json.Linq; |
| using Seer.SeerSocket; |
| |
| public class ExplortStatisticBgService : BackgroundService |
| { |
| private readonly SqliteDbContext ctx; |
| private readonly ILogger<ExplortStatisticBgService> logger; |
| private readonly IServiceScope serviceScope; |
| private readonly SeerSocket seer; |
| public ExplortStatisticBgService(IServiceScopeFactory scopeFactory) |
| { |
| this.serviceScope = scopeFactory.CreateScope(); |
| var sp = serviceScope.ServiceProvider; |
| this.ctx = sp.GetRequiredService<SqliteDbContext>(); |
| this.logger = sp.GetRequiredService<ILogger<ExplortStatisticBgService>>(); |
| this.seer = sp.GetRequiredService<SeerSocket>(); |
| } |
| protected override async Task ExecuteAsync(CancellationToken stoppingToken) |
| { |
| while (!stoppingToken.IsCancellationRequested) |
| { |
| try |
| { |
| await DoExecuteAsync(); |
| await Task.Delay(2000); |
| } |
| catch (Exception ex) |
| { |
| logger.LogError(ex, "获取用户统计数据失败"); |
| await Task.Delay(1000); |
| } |
| } |
| } |
| private async Task DoExecuteAsync() |
| { |
| var msg = seer.Send(0x0410, """{"motor_names": ["motor1"]}""", 19204); |
| System.Console.WriteLine(msg); |
| |
| string filePath = "/Users/song/Code/Dotnet.Seer/常驻后台的数据导出服务/Db/all1.json"; |
| |
| using (FileStream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) |
| { |
| using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8)) |
| { |
| writer.Write(msg); |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| } |
| public override void Dispose() |
| { |
| base.Dispose(); |
| serviceScope.Dispose(); |
| } |
| } |
| |
| |
| |
| |
常驻后台的数据导出服务/Request.http
| # Request.http |
| |
| ```sh |
| |
| @hostname = localhost |
| @port = 5015 |
| @host = http://{{hostname}}:{{port}} |
| |
| ### GET |
| |
| GET {{host}}/user HTTP/1.1 |
| |
| |
| |
| |
| POST {{host}}/user HTTP/1.1 |
| content-type: application/json |
| |
| { |
| "nickName": "Bruce" |
| } |
| |
| |
| |
| |
| GET {{host}}/WeatherForecast/中国 HTTP/1.1 |
| |
| |
| |
| |
| GET {{host}}/WeatherForecast/新西兰 HTTP/1.1 |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| # `常驻后台的数据导出服务/User.cs` |
| |
| ```cs |
| |
| public record User |
| { |
| public Guid guid { get; set; } |
| public string NickName { get; set; } |
| } |
常驻后台的数据导出服务/appsettings.json
| { |
| "Logging": { |
| "LogLevel": { |
| "Default": "Information", |
| "Microsoft.AspNetCore": "Warning" |
| } |
| }, |
| "AllowedHosts": "*", |
| "ConnectionStrings": { |
| "Default": "Data Source=./Db/test.db;", |
| "AgvIpAddress": "127.0.0.1" |
| }, |
| "Agv":{ |
| "AgvIp": "127.0.0.1" |
| } |
| } |
| |
常驻后台的数据导出服务/UserContracts.cs
| |
| public record UserRequest(string NickName); |
常驻后台的数据导出服务/UserConfig.cs
| using Microsoft.EntityFrameworkCore; |
| using Microsoft.EntityFrameworkCore.Metadata.Builders; |
| |
| class UserConfig : IEntityTypeConfiguration<User> |
| { |
| public void Configure(EntityTypeBuilder<User> builder) |
| { |
| builder.ToTable("T_Users"); |
| builder.HasKey(u => u.guid); |
| } |
| |
| } |
| |
| |
常驻后台的数据导出服务/MyDesignTimeDbContextFactory.cs
| using Microsoft.EntityFrameworkCore; |
| using Microsoft.EntityFrameworkCore.Design; |
| |
| class MyDesignTimeDbContextFactory : IDesignTimeDbContextFactory<SqliteDbContext> |
| { |
| public SqliteDbContext CreateDbContext(string[] args) |
| { |
| DbContextOptionsBuilder<SqliteDbContext> builder = new(); |
| |
| |
| string connStr = "Data Source=Db/test.db"; |
| builder.UseSqlite(connStr); |
| return new SqliteDbContext(builder.Options); |
| } |
| |
| } |
常驻后台的数据导出服务/appsettings.Development.json
| { |
| "Logging": { |
| "LogLevel": { |
| "Default": "Information", |
| "Microsoft.AspNetCore": "Warning" |
| } |
| } |
| } |
| |
常驻后台的数据导出服务/SqliteDbContext.cs
| using Microsoft.EntityFrameworkCore; |
| |
| public class SqliteDbContext : DbContext |
| { |
| public DbSet<User> Users { get; set; } |
| public SqliteDbContext(DbContextOptions<SqliteDbContext> options) |
| : base(options) |
| { |
| } |
| protected override void OnModelCreating(ModelBuilder modelBuilder) |
| { |
| base.OnModelCreating(modelBuilder); |
| modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly); |
| } |
| } |
常驻后台的数据导出服务/Program.cs
| using Microsoft.AspNetCore.Identity; |
| using Microsoft.EntityFrameworkCore; |
| using Seer.SeerSocket; |
| |
| var builder = WebApplication.CreateBuilder(args); |
| |
| |
| builder.Services.AddControllers(); |
| builder.Services.AddEndpointsApiExplorer(); |
| builder.Services.AddSwaggerGen(); |
| builder.Services.AddSingleton<SeerSocket>(sp=>new SeerSocket("127.0.0.1",true)); |
| |
| |
| IServiceCollection services = builder.Services; |
| |
| services.AddHostedService<ExplortStatisticBgService>(); |
| services.AddDbContext<SqliteDbContext>(opt => { |
| string connStr = builder.Configuration.GetConnectionString("Default"); |
| opt.UseSqlite(connStr); |
| }); |
| |
| |
| var app = builder.Build(); |
| |
| if (app.Environment.IsDevelopment()) |
| { |
| app.UseSwagger(); |
| app.UseSwaggerUI(); |
| } |
| |
| app.UseHttpsRedirection(); |
| |
| app.UseAuthorization(); |
| |
| app.MapControllers(); |
| |
| app.Run(); |
| |
| |
常驻后台的数据导出服务/Db/all1.json
| {"motor_names": ["motor1"]}����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� |
常驻后台的数据导出服务/Controllers/UserController.cs
| using Microsoft.AspNetCore.Mvc; |
| using Microsoft.EntityFrameworkCore; |
| using Seer.SeerSocket; |
| |
| namespace 常驻后台的数据导出服务.Controllers; |
| |
| [ApiController] |
| [Route("[controller]")] |
| public class UserController : ControllerBase |
| { |
| |
| private readonly ILogger<UserController> logger; |
| private readonly SqliteDbContext dbContext; |
| |
| public UserController(ILogger<UserController> logger, SqliteDbContext dbContext,SeerSocket seer) |
| { |
| this.logger = logger; |
| this.dbContext = dbContext; |
| } |
| |
| [HttpGet] |
| public async Task<IEnumerable<User>> Get() |
| { |
| return await dbContext.Users.ToListAsync(); |
| } |
| |
| [HttpPost] |
| public async Task Save(UserRequest user) |
| { |
| dbContext.Users.Add(new User { NickName = user.NickName }); |
| await dbContext.SaveChangesAsync(); |
| } |
| } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
2023-02-15 flask_openv_video_streaming_来自miguelgrinberg大佬_写pythonsocketio的那个
2023-02-15 flask_socketio_rasip_video_stream_opencv
2022-02-15 autojs 读取多行文本 一行一行读取文本
2022-02-15 微信公众号 话题链接提取
2022-02-15 创建多层目录 文件写入
2022-02-15 微信公众号 爬虫 提取url
2022-02-15 cheerio 解析新浪博客目录列表