日常生活的交流与学习

首页 新随笔 联系 管理

常驻后台的数据导出服务/常驻后台的数据导出服务.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;  // 0x5A
    public byte version; // 0x01
    public ushort number; // 0-65536
    public uint length; // 数据区长度,json序列化数据长度
    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));

    }

    // 使用键来访问特定的TcpClient对象
    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;
                }
            }
            // var content = BitConverter.ToString(SeerMessageHeadToBytes(recv_head)).Replace("-", " ");
            // Console.WriteLine(content);
            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 = (T)Marshal.PtrToStructure(bufferHandler, typeof(T));
        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";
		// 使用UTF-8编码写入文件
		using (FileStream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
		{
			using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8))
			{
				writer.Write(msg);
			}
		}
		// JObject jsonObject = JObject.Parse(File.ReadAllText(filePath));
		// Console.WriteLine(jsonObject.ToString());






		// var users =  await this.ctx.Users.ToListAsync();
		// foreach(var user in users){
		// 	Console.WriteLine($"{DateTime.Now} : User : {user.NickName}");
		// 	break;
		// }

	}
	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

POST {{host}}/user HTTP/1.1
content-type: application/json

{
    "nickName": "Bruce"
}


### GET 中国

GET {{host}}/WeatherForecast/中国 HTTP/1.1


### GET 新西兰

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 = Environment.GetEnvironmentVariable("ConnectionStrings:Default");
		// builder.UseSqlServer(connStr);
		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();
    }
}
posted on 2024-02-15 23:12  lazycookie  阅读(18)  评论(0编辑  收藏  举报