服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#与java TCP通道加密通信实例

C#与java TCP通道加密通信实例

2022-12-07 11:42我打农村来 C#

这篇文章主要介绍了C#与java TCP通道加密通信,文章通过真实的案例详细讲解说明C#与java TCP通道加密通信的相关资料,需要的小伙伴可以参考一下

1、背景说明

公司收费系统需要与银行做实时代收对接,业务协议使用我们收费系统的标准。但是银行要求在业务协议的基础上,使用银行的加密规则。

  • 采用MD5计算报文摘要,保证数据的完整性
  • 采用RSA256对摘要进行签名,保证报文的合法性
  • 采用AES进行对称加密,保证报文的私密性

我们几个人一评估,在业务报文上加一套加密方案,加密方法又是通用的,这个能有什么问题,没问题。

2、测试证书

银行发来的测试证书在这里

后来才知道这应该叫java版格式,而且这个证书经验证是正确的,可正常签名、验签的。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDllhc9gw7aIuv8
URnf8PtPRJZww26OeSsTa1GHtuqHdjCaosBXKWaC2/SxV3lsURizFVY+HhvH6zgq
NCWhSbnwd5ucq8ZiBkb29kIbb9oVKftxpsMTfZdAgXReUPg1cE5zxLvpmSM8ggw9
2fOq/CgYgbingzAScYR5MmMgH5PwIEVh7MiloS5fMx9HWDuKAZgdXjaZHB5UL8uu
vb83iytKJIEmS346X41jCM8UQwL4hRaPvtouGSIz+oiDpotPfJQtJVzP1P/bvlQs
RJHSn1a5aDo+ygH231+PKdfKzhwxDDMeI3Yy2zxqJKtHpVc033O2yfvn5TlQ79P0
j/hswY0fAgMBAAECggEBAKZKkWjHfcF4W+91GsW+uXiP2Fuy4mgl0ZKOQA6J6dPW
Qpwu2BwJ66tLADBXiKZxEu/bu4zgqASlFhhTjxIE4b4QFFFlhhrIKyyD8BwJZy+/
KdYHEPMUG7LoUU5jXXTvdJOb4vPvLLuOAqnmLP0jCTO++e2zMuWY/Xf/jBbfaHsa
tSM3PHYN/zlTMDyFqfDc6ig+iKejW0dnNBQZpFytijpYgW3QS6XKknDRoQ0V1vpj
oCCUMlfe8tottGoBt1Q8qrNKxFb9dyXXkGx/QgDfv8A+kWv1WuwYQGose9Gu0L28
TWGOfHS399oJffJdwa/o2no+KCaKjjL5dCIjzLDm8QECgYEA/t4JgS32JS8cxyEK
Hh0tGOZhvsh/f2IOi1+pAtBKCQan34n/NCBUeyn8Ep/K95A+bPMIltaoUZYkBTGF
bVsqdkcyG19qsV5B2ldyfvBoSpwsS7oLcV78EUPLBClCpYfmbq/MEdYTysJsjKRc
ROR0p30Cu/VEP72WTyY4zMy6yp8CgYEA5ptKmDAud48hlI7gNWkKIVEH16cg+0fS
a1JgrBUZHOoVTuK8xMUxsGyYeYYolXd7I5Q4vdZwTzjGkAzCMtHzhMUSbzt6i04o
rDkfB3HEXgoIiGvChh+CjYOhc6aqKd3vFOwVyqZ0s5slc7EF4qWy9ZWD3hwWGfEE
XkO1Zc/MrYECgYANq2UBG7D2/5bgi0IaqV/w1PJrJB/Kejzjdsb+0qMV5th8Ic+h
QRam4HKXoSBmtMLUXxiX1n2CmrXl3WkVm20kmN70HuL/Dloj1sraShSd49BwY1MX
yotkdale2MOtUyOlziH41u2K03C0/l/AhixHi2npINd/P7DfH+KuAVEHawKBgA2I
c3o26aMujSPwtour3GJUJQes0Syt7FVMAkxW+KBPxGxatgU+JUpbNR98lgkfd+SA
oEvTt8eOZ2iwtvzQgV/7SLeqX+io744b1AxVytZR9Go9GK9SThEL9n+Y+kd2tL8f
k6/O0O5xXmNJsjS40KXE3nY8Y7emA0Gc65pL9ZEBAoGBANPd8FP04tTtyqiunE8G
JrOIQGtCUoEnp4gJV5VVGus19qVf6rVMr1YEMlojxgujcaQJtE878Zep6ur2WeZu
VEQOqqXRLwKBTaWYA0iabhUDd/nAh5cCjBfcYrfdnQonNrBJi5AccbfUl6FEhkoF
XQUoc1mnauKcCB1ACvtBRNGI
-----END PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5ZYXPYMO2iLr/FEZ3/D7
T0SWcMNujnkrE2tRh7bqh3YwmqLAVylmgtv0sVd5bFEYsxVWPh4bx+s4KjQloUm5
8HebnKvGYgZG9vZCG2/aFSn7cabDE32XQIF0XlD4NXBOc8S76ZkjPIIMPdnzqvwo
GIG4p4MwEnGEeTJjIB+T8CBFYezIpaEuXzMfR1g7igGYHV42mRweVC/Lrr2/N4sr
SiSBJkt+Ol+NYwjPFEMC+IUWj77aLhkiM/qIg6aLT3yULSVcz9T/275ULESR0p9W
uWg6PsoB9t9fjynXys4cMQwzHiN2Mts8aiSrR6VXNN9ztsn75+U5UO/T9I/4bMGN
HwIDAQAB
-----END PUBLIC KEY-----

C#版本证书在这里,这个是后来正确的测试证书转换的C#版本,与上面的java版本对应

私钥

?
1
2
<RSAKeyValue><Modulus>5ZYXPYMO2iLr/FEZ3/D7T0SWcMNujnkrE2tRh7bqh3YwmqLAVylmgtv0sVd5bFEYsxVWPh4bx+s4KjQloUm58HebnKvGYgZG9vZCG2/aFSn7cabDE32XQIF0XlD4NXBOc8S76ZkjPIIMPdnzqvwoGIG4p4MwEnGEeTJjIB+T8CBFYezIpaEuXzMfR1g7igGYHV42mRweVC/Lrr2/N4srSiSBJkt+Ol+NYwjPFEMC+IUWj77aLhkiM/qIg6aLT3yULSVcz9T/275ULESR0p9WuWg6PsoB9t9fjynXys4cMQwzHiN2Mts8aiSrR6VXNN9ztsn75+U5UO/T9I/4bMGNHw==</Modulus><Exponent>AQAB</Exponent><P>/t4JgS32JS8cxyEKHh0tGOZhvsh/f2IOi1+pAtBKCQan34n/NCBUeyn8Ep/K95A+bPMIltaoUZYkBTGFbVsqdkcyG19qsV5B2ldyfvBoSpwsS7oLcV78EUPLBClCpYfmbq/MEdYTysJsjKRcROR0p30Cu/VEP72WTyY4zMy6yp8=</P><Q>5ptKmDAud48hlI7gNWkKIVEH16cg+0fSa1JgrBUZHOoVTuK8xMUxsGyYeYYolXd7I5Q4vdZwTzjGkAzCMtHzhMUSbzt6i04orDkfB3HEXgoIiGvChh+CjYOhc6aqKd3vFOwVyqZ0s5slc7EF4qWy9ZWD3hwWGfEEXkO1Zc/MrYE=</Q><DP>DatlARuw9v+W4ItCGqlf8NTyayQfyno843bG/tKjFebYfCHPoUEWpuByl6EgZrTC1F8Yl9Z9gpq15d1pFZttJJje9B7i/w5aI9bK2koUnePQcGNTF8qLZHWpXtjDrVMjpc4h+NbtitNwtP5fwIYsR4tp6SDXfz+w3x/irgFRB2s=</DP><DQ>DYhzejbpoy6NI/C2i6vcYlQlB6zRLK3sVUwCTFb4oE/EbFq2BT4lSls1H3yWCR935ICgS9O3x45naLC2/NCBX/tIt6pf6KjvjhvUDFXK1lH0aj0Yr1JOEQv2f5j6R3a0vx+Tr87Q7nFeY0myNLjQpcTedjxjt6YDQZzrmkv1kQE=</DQ><InverseQ>093wU/Ti1O3KqK6cTwYms4hAa0JSgSeniAlXlVUa6zX2pV/qtUyvVgQyWiPGC6NxpAm0Tzvxl6nq6vZZ5m5URA6qpdEvAoFNpZgDSJpuFQN3+cCHlwKMF9xit92dCic2sEmLkBxxt9SXoUSGSgVdBShzWadq4pwIHUAK+0FE0Yg=</InverseQ><D>pkqRaMd9wXhb73Uaxb65eI/YW7LiaCXRko5ADonp09ZCnC7YHAnrq0sAMFeIpnES79u7jOCoBKUWGFOPEgThvhAUUWWGGsgrLIPwHAlnL78p1gcQ8xQbsuhRTmNddO90k5vi8+8su44CqeYs/SMJM7757bMy5Zj9d/+MFt9oexq1Izc8dg3/OVMwPIWp8NzqKD6Ip6NbR2c0FBmkXK2KOliBbdBLpcqScNGhDRXW+mOgIJQyV97y2i20agG3VDyqs0rEVv13JdeQbH9CAN+/wD6Ra/Va7BhAaix70a7QvbxNYY58dLf32gl98l3Br+jaej4oJoqOMvl0IiPMsObxAQ==</D></RSAKeyValue>
公钥
?
1
<RSAKeyValue><Modulus>5ZYXPYMO2iLr/FEZ3/D7T0SWcMNujnkrE2tRh7bqh3YwmqLAVylmgtv0sVd5bFEYsxVWPh4bx+s4KjQloUm58HebnKvGYgZG9vZCG2/aFSn7cabDE32XQIF0XlD4NXBOc8S76ZkjPIIMPdnzqvwoGIG4p4MwEnGEeTJjIB+T8CBFYezIpaEuXzMfR1g7igGYHV42mRweVC/Lrr2/N4srSiSBJkt+Ol+NYwjPFEMC+IUWj77aLhkiM/qIg6aLT3yULSVcz9T/275ULESR0p9WuWg6PsoB9t9fjynXys4cMQwzHiN2Mts8aiSrR6VXNN9ztsn75+U5UO/T9I/4bMGNHw==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>

3、复制粘贴加密算法

百度C#RSA签名,大差不差,还简洁明了,很快签名、验签方法就出来啦。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/// <summary>
/// RSA签名
/// </summary>
/// <param name="privateKey">私钥</param>
/// <param name="data">待签名的内容</param>
/// <returns></returns>
public static string RSASignCSharp(string data, string privateKey, string hashAlgorithm = "SHA256", string encoding = "UTF-8")
{
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
    rsa.FromXmlString(privateKey); //加载私钥  
    var dataBytes = Encoding.GetEncoding(encoding).GetBytes(data);
    var HashbyteSignature = rsa.SignData(dataBytes, hashAlgorithm);
    return Convert.ToBase64String(HashbyteSignature);
}
 
/// <summary>
/// 验证签名
/// </summary>
/// <param name="data"></param>
/// <param name="signature"></param>
/// <param name="encoding"></param>
/// <returns></returns>
public static bool VerifyCSharp(string data, string publicKey, string signature, string hashAlgorithm = "SHA256", string encoding = "UTF-8")
{
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
    //导入公钥,准备验证签名
    rsa.FromXmlString(publicKey);
    //返回数据验证结果
    byte[] Data = Encoding.GetEncoding(encoding).GetBytes(data);
    byte[] rgbSignature = Convert.FromBase64String(signature);
    return rsa.VerifyData(Data, hashAlgorithm, rgbSignature);
}

王婆卖瓜,自卖自夸。

来波自签自验吧,竟然不过。怎么就不过了呢,越简单越感觉无处下手调试呀。算法都封装了,那只可能是参数的问题了。

4、证书格式转换

主要原因是javaC#采用的公钥、私钥存储格式不一致,导致无法直接使用银行提供的java版证书,需要进行格式转换,转换成C#能够识别的证书。这里是转换方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/// <summary>
/// RSA公钥格式转换,java->.net
/// </summary>
/// <param name="publicKey">java生成的公钥</param>
/// <returns></returns>
public static string RSAPublicKeyJava2DotNet(string publicKey)
{
    RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
    return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",
        Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
        Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
 
}
/// <summary>
/// RSA私钥格式转换,java->.net
/// </summary>
/// <param name="privateKey">java生成的私钥</param>
/// <returns></returns>
public static string RSAPrivateKeyJava2DotNet(string privateKey)
{
    RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey));
 
    return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",
        Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()),
        Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()),
        Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()),
        Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()),
        Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()),
        Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()),
        Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()),
        Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned()));
}

结果证书转换也不过,直接抛异常。然后就反复梳理代码逻辑,总觉得转换方法不对,各种百度。

众里寻他千百度。蓦然回首,那人却在,灯火阑珊处。

这大概就是这种比较不可思议问题的纠结吧,证书不会有错吧?

出于验证的目的我们找到了线上在用的正常证书,进行转换,正常转换,签名验签正常。不至于吧,我又找来了java的转换方法。下面是java代码,转换java证书为C#格式:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package com.company;
 
 
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
 
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
 
public class CerJava2CSharp {
    public static void main(String[] args)
    {
        String tes="java版私钥证书";
        byte[] temp=b64decode(tes);
        String ver=getRSAPrivateKeyAsNetFormat(temp);//转换私钥
 
        String tes1="java版公钥证书";
        byte[] temp1=b64decode(tes1);
        String ver1=getRSAPublicKeyAsNetFormat(temp1);//转换公钥
        String temp2= ver1;
 
    }
    
    public static String getRSAPrivateKeyAsNetFormat(byte[] encodedPrivkey) {
        try {
            StringBuffer buff = new StringBuffer(1024);
 
            PKCS8EncodedKeySpec pvkKeySpec = new PKCS8EncodedKeySpec(
                    encodedPrivkey);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            RSAPrivateCrtKey pvkKey = (RSAPrivateCrtKey) keyFactory
                    .generatePrivate(pvkKeySpec);
 
            buff.append("<RSAKeyValue>");
            buff.append("<Modulus>"
                    + b64encode(removeMSZero(pvkKey.getModulus().toByteArray()))
                    + "</Modulus>");
 
            buff.append("<Exponent>"
                    + b64encode(removeMSZero(pvkKey.getPublicExponent()
                    .toByteArray())) + "</Exponent>");
 
            buff.append("<P>"
                    + b64encode(removeMSZero(pvkKey.getPrimeP().toByteArray()))
                    + "</P>");
 
            buff.append("<Q>"
                    + b64encode(removeMSZero(pvkKey.getPrimeQ().toByteArray()))
                    + "</Q>");
 
            buff.append("<DP>"
                    + b64encode(removeMSZero(pvkKey.getPrimeExponentP()
                    .toByteArray())) + "</DP>");
 
            buff.append("<DQ>"
                    + b64encode(removeMSZero(pvkKey.getPrimeExponentQ()
                    .toByteArray())) + "</DQ>");
 
            buff.append("<InverseQ>"
                    + b64encode(removeMSZero(pvkKey.getCrtCoefficient()
                    .toByteArray())) + "</InverseQ>");
 
            buff.append("<D>"
                    + b64encode(removeMSZero(pvkKey.getPrivateExponent()
                    .toByteArray())) + "</D>");
            buff.append("</RSAKeyValue>");
 
            return buff.toString().replaceAll("[ \t\n\r]", "");
        } catch (Exception e) {
            System.err.println(e);
            return null;
        }
    }
 
    public static String getRSAPublicKeyAsNetFormat(byte[] encodedPrivkey) {
        try {
            StringBuffer buff = new StringBuffer(1024);
 
            PKCS8EncodedKeySpec pvkKeySpec = new PKCS8EncodedKeySpec(encodedPrivkey);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            RSAPublicKey pukKey=(RSAPublicKey) keyFactory.generatePublic(new X509EncodedKeySpec(encodedPrivkey));
            // RSAPrivateCrtKey pvkKey = (RSAPrivateCrtKey) keyFactory.generatePrivate(pvkKeySpec);
 
            //PublicKey publicKey =KeyFactory.getInstance("RSA").generatePublic(pvkKeySpec);
            buff.append("<RSAKeyValue>");
            buff.append("<Modulus>"
                    + b64encode(removeMSZero(pukKey.getModulus().toByteArray()))
                    + "</Modulus>");
            buff.append("<Exponent>"
                    + b64encode(removeMSZero(pukKey.getPublicExponent()
                    .toByteArray())) + "</Exponent>");
            buff.append("</RSAKeyValue>");
            return buff.toString().replaceAll("[ \t\n\r]", "");
        } catch (Exception e) {
            System.err.println(e);
            return null;
        }
    }
 
    public static String encodePublicKeyToXml(PublicKey key) {
        if (!RSAPublicKey.class.isInstance(key)) {
            return null;
        }
        RSAPublicKey pubKey = (RSAPublicKey) key;
        StringBuilder sb = new StringBuilder();
 
        sb.append("<RSAKeyValue>");
        sb.append("<Modulus>")
                .append(Base64.encode(pubKey.getModulus().toByteArray()))
                .append("</Modulus>");
        sb.append("<Exponent>")
                .append(Base64.encode(pubKey.getPublicExponent()
                        .toByteArray())).append("</Exponent>");
        sb.append("</RSAKeyValue>");
        return sb.toString();
    }
 
    public static byte[] removeMSZero(byte[] data) {
        byte[] data1;
        int len = data.length;
        if (data[0] == 0) {
            data1 = new byte[data.length - 1];
            System.arraycopy(data, 1, data1, 0, len - 1);
        } else
            data1 = data;
 
        return data1;
    }
 
    public static String b64encode(byte[] data) {
 
        String b64str = new String(Base64.encode(data));
        return b64str;
    }
 
    public static byte[] b64decode(String data) {
        byte[] decodeData = Base64.decode(data);
        return decodeData;
    }
}

经验证,仍然无法转换,好吧,实锤了,证书有问题。至于是什么原因造成的证书问题,不太清楚。更换证书后,转换、签名、验签一切OK。

5、PS1 RSA证书格式

我们通常看到的比较多的证书对形式,pfx证书包含了公钥信息和私钥信息。cer证书只包含公钥信息。pfx证书既可以导出为pfx证书,也可以导出为cer证书。pfx证书导出时,会提示是否导出私钥,导出私钥即pfx证书,不到出则是cer证书。pfx证书导入、导出和程序加载时,是需要提供证书密码的。

  • 私钥证书常见格式:pfx p12 pem key
  • 公钥证书常见格式:pem crt/cer key

到此这篇关于C#java TCP通道加密通信实例的文章就介绍到这了,更多相关C#java TCP通道加密通信内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

6、参考博文

OpenSSL中证书格式的区别以及格式的转换

RSA密钥——JAVA与C#的区别和联系

原文链接:https://www.cnblogs.com/zhangdk/p/RSA.html?utm_source=tuicool&utm_medium=referral

延伸 · 阅读

精彩推荐
  • C#C#中explicit与implicit的深入理解

    C#中explicit与implicit的深入理解

    这篇文章主要给大家介绍了关于C#中explicit与implicit的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用C#具有一定的参考学习价值,需要...

    依乐祝11832022-07-22
  • C#谈C# using的用法与好处

    谈C# using的用法与好处

    这篇文章主要为大家详细介绍了C# using的用法与好处,具体分析了using指令调用的Dispose()方法,感兴趣的朋友可以参考一下...

    net小伙10942021-11-21
  • C#C# WinForm制作异形窗体与控件的方法

    C# WinForm制作异形窗体与控件的方法

    这篇文章主要介绍了C# WinForm制作异形窗体与控件的方法,结合实例形式分析了WinForm制作异形窗体与控件的原理、实现步骤与相关操作技巧,需要的朋友可以参...

    aparche6502022-01-05
  • C#C#读写文本文件(.txt)的方法实例

    C#读写文本文件(.txt)的方法实例

    读写文本文件其实是件很简单的事情,这篇文章主要给大家介绍了关于C#读写文本文件(.txt)的相关资料,需要的朋友可以参考下...

    君莫笑·秋7632022-11-17
  • C#unity实现透明水波纹扭曲

    unity实现透明水波纹扭曲

    这篇文章主要为大家详细介绍了unity实现透明水波纹扭曲,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    请输入姓名5602022-09-06
  • C#C#设置Word文本框中改变文字方向的方法

    C#设置Word文本框中改变文字方向的方法

    在Word中可插入文本框,默认情况下插入的文本框中的文字方向为横向排列,对于一些特殊文档的设计要求,需要改变文字方向,本文就详细的介绍一下使用...

    E-iceblue9652022-11-23
  • C#UGUI实现图片拖拽功能

    UGUI实现图片拖拽功能

    这篇文章主要为大家详细介绍了UGUI实现图片拖拽功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    u01423092310472022-03-11
  • C#C#调用Java类的实现方法

    C#调用Java类的实现方法

    以下是对使用C#调用Java类的实现方法进行了详细的介绍,需要的朋友可以过来参考下...

    C#教程网6432022-01-06