锘??xml version="1.0" encoding="utf-8" standalone="yes"?> GitExtensions and Git fail: But TortoiseGit is OK.
Copy my RSA key file rsa.ppk that TortoiseGit uses as ~/.ssh/id_rsa: Open TortoiseGit/bin/puttygen.exe, load rsa.ppk, then Convensionis->Export OpenSSH key as ~/.ssh/id_rsa: id_rsa begins with: (Jin Qing's Column, Dec., 2021) Try to find out why Orleans need a DeathVoteExpirationTimeout config. DeathVoteExpirationTimeout is only used by GetFreshVotes(), which has 3 occurence: GetFreshVotes() uses this expiration time to ignore old voter: (Jin Qing's Column, Dec., 2021) GitExtension is a good tool. After a long time of usage, my branch list finally reaches over a full screen, and it is hard to select the branch I want. GitExtension always remembers all the branches of remote and local, even they have been deleted. I tried to find a way to delete these branches which are already merged, but resulted in futile. It has a plugin names "Delete obsolete branches", but I don't know how to use it. Finally I renamed the work directory, and cloned a new one, which clears all the branches.
It seems that these branches are stored in local .git directory.
If let GitExt open the renamed directory, these branches reappears. Reference: (Jin Qing's Column, Nov. 3, 2021) When deployed to a cluster of nodes,
Orleans internally implements a protocol to manage it's silos,
including discovery, failure and reconfigure,
which is called cluster membership management. Orleans has clustering membership providers for: Azure, SQL server, Zookeeper. Clustering provider is one of key aspects of silo configuration. OrleansContrib/Orleans.Clustering.Kubernetes
is a clustering provider for running Orleans cluster on Kubernetes. Tell silo to use Kubernetes as the Cluster Membership Provider: InitializeMembershipTable() TryInitClusterVersion() DeleteMembershipTableEntries(string clusterId) InsertRow(...) ReadAll() GetClusterVersion() GetSilos() ReadRow(SiloAddress key) UpdateIAmAlive(MembershipEntry entry) UpdateRow(...) CleanupDefunctSiloEntries(DateTimeOffset beforeDate) The operators to NamespacedCustomObject are: Two CRDs, Custom resource objects are stored in etcd of Kubernetes. (Jin Qing's Column, Nov. 2, 2021) Virtual Actor is a concept invented by Microsoft Orleans, which is a framework of distributed actor. Orleans: Distributed Virtual Actors for Programmability and Scalability describes the virtual programming model. The virtual actor is analogous to virtual memory. Virtual actors are mapped to physical arctors instances in the running servers. Virtualization of actors in Orleans has 4 facets: Perpetual existence Automatic instantiation Location transparency Automatic scale out 2 activation modes: Single activation (default): Only one simultaneous actor is allowed Stateless worker: Many activations of an actor are created Actor viruliaztion greatly simplifes the programming, since it gets rid of the burden of actor lifecycle control. (Jin Qing's Column, Oct. 25, 2021) Reading "The Evolution of Distributed Systems on Kubernetes" from Bilgin Ibryam. https://www.infoq.com/articles/distributed-systems-kubernetes/ What are the purpose of projects like Dapr, Istio, Knative? How can they change the world? The needs of distributed systems: Business logic Other enterprise service bus (ESB): not distributed Kubernetes: Lifecycle Istio: Networking Knative: scale Networking, resource binding, state Write business logic as another runtime. Here runtime is a process? Faas is not the best. Multi-runtime microservice maybe is. In addition to public and private, Rust allows users to declare an item as visible only within a given scope. The rules for 鏈嶅姟鍙戠幇鐨勭粍浠?/p> (閲戝簡鐨勪笓鏍?2018.5) 鏈嶅姟鍙戠幇鏈変互涓嬬粍浠訛細 Service Registry 鏈嶅姟娉ㄥ唽涓績 緇存姢鏈嶅姟鐨勫垪琛紝鎻愪緵鏌ヨ銆備竴鑸疄鐜頒負鍒嗗竷寮忛敭鍊煎瓨鍌ㄦ暟鎹簱銆?/p> Registrator 娉ㄥ唽鍣?/p> 鐩戝惉鏈嶅姟鍒涘緩鍜屽垹闄や簨浠訛紝騫跺湪鏈嶅姟娉ㄥ唽涓績鍔ㄦ佹敞鍐屾垨娉ㄩ攢鏈嶅姟銆?/p> Health Checker 鍋ュ悍媯鏌ュ櫒 鐩戣鏈嶅姟鏄惁鍋ュ悍錛屽茍鍦ㄦ湇鍔℃敞鍐屼腑蹇冨姩鎬佹洿鏂版湇鍔°?/p> Load balancer 璐熻澆鍧囪 鍣?/p> 灝嗘湇鍔¤姹傚垎鏁e埌鍚勪釜鏈嶅姟鍣ㄣ?/p>
"git" pull --progress "origin"
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
Done
Press Enter or Esc to exit...
git.exe pull --progress -v --no-rebase "origin"
From github.com:jinq0123/recastnavigation
= [up to date] master -> origin/master
= [up to date] release-2.0 -> origin/release-2.0
Already up to date.
ssh -T
shows that the reason is there is no id files:
PS d:\github> ssh -vT git@github.com
OpenSSH_for_Windows
debug1: Connecting to github.com [20.205.243.166] port 22.
debug1: Connection established.
debug1: identity file C:\\Users\\jinqing/.ssh/id_rsa type -1
debug1: identity file C:\\Users\\jinqing/.ssh/id_xmss-cert type -1
debug1: Authenticating to github.com:22 as 'git'
debug1: Host 'github.com' is known and matches the ED25519 host key.
debug1: Found key in C:\\Users\\jinqing/.ssh/known_hosts:2
debug1: Will attempt key: C:\\Users\\jinqing/.ssh/id_rsa
debug1: Will attempt key: C:\\Users\\jinqing/.ssh/id_xmss
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey
debug1: Next authentication method: publickey
debug1: Trying private key: C:\\Users\\jinqing/.ssh/id_rsa
debug1: Trying private key: C:\\Users\\jinqing/.ssh/id_xmss
debug1: No more authentication methods to try.
git@github.com: Permission denied (publickey).
PS d:\github>
PS D:\jinqing\github_jinq\recastnavigation> ssh -T git@github.com
Load key "C:\\Users\\jinqing/.ssh/id_rsa": invalid format
git@github.com: Permission denied (publickey).
PS D:\jinqing\github_jinq\recastnavigation>
PS D:\jinqing\github_jinq\recastnavigation> ssh -T git@github.com
Hi jinq0123! You've successfully authenticated, ...
-----BEGIN RSA PRIVATE KEY-----
]]>DeathVoteExpirationTimeout - Expiration time in seconds for death vote in the membership table. Default is 120 seconds
GetFreshVotes
class ClusterHealthMonitor
{
...
private UpdateMonitoredSilos(...)
{
...
bool isSuspected = candidateEntry.GetFreshVotes(now, DeathVoteExpirationTimeout).Count > 0;
...
}
}
class LocalSiloHealthMonitor
{
...
private int CheckSuspectingNodes(DateTime now, List<string> complaints)
{
...
var freshVotes = membershipEntry.GetFreshVotes(now, DeathVoteExpirationTimeout);
...
}
...
}
class MembershipTableManager
{
...
public TryToSuspectOrKill(SiloAddress silo)
{
...
// get all valid (non-expired) votes
var freshVotes = entry.GetFreshVotes(DateTime.UtcNow, DeathVoteExpirationTimeout);
...
}
...
}
internal GetFreshVotes(DateTime now, TimeSpan expiration)
{
...
foreach (var voter in this.SuspectTimes)
{
var otherVoterTime = voter.Item2;
if (now.Subtract(otherVoterTime) < expiration)
{
result.Add(voter);
}
}
return result.ToImmutable();
}
]]>
]]>Orleans.Clustering.Kubernetes
var silo = new SiloBuilder()
...
.UseKubeMembership()
...
.Build();
Interface
UseKubeMembership()
instantiates a KubeMembershipTable
which implements
IMembershipTable
. public interface IMembershipTable
{
Task InitializeMembershipTable(bool tryInitTableVersion);
Task DeleteMembershipTableEntries(string clusterId);
Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate);
Task<MembershipTableData> ReadRow(SiloAddress key);
Task<MembershipTableData> ReadAll();
Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion);
Task<bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion);
Task UpdateIAmAlive(MembershipEntry entry);
}
Implement
KubeMembershipTable
access Kubernetes API server to read and write silo entry CRD.
CRD
ClusterVersion
and Silo
are defined in files:
]]>
]]>Modern distributed systems
Monolithic architecture
Cloud-native architecture
Service Mesh
Serverless
Dapr
Trends
Multi-runtime microservice
What comes after microservice
]]>
https://doc.rust-lang.org/std/ops/trait.Deref.html
```
use std::ops::Deref;
struct DerefExample<T> {
value: T
}
impl<T> Deref for DerefExample<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
let x = DerefExample { value: 'a' };
assert_eq!('a', *x);
```
Deref coercion can be used in newtype:
```
struct MyI32(i32)
impl Deref for MyI32 {
type Target = i32;
fn deref(&self) -> &Self::Target {
&self.0
}
}
```
]]>unwrap
on Result. If the type is Err, it will panic and crash the program. The only exception is if it has already been checked for error previously or in test code.unwrap
on Option for the same reason if the type is None as Result is Err.
]]>pub(in path)
, pub(crate)
, pub(super)
, and pub(self)
pub
restrictions are as follows:pub(in path)
makes an item visible within the provided path
. path
must be an ancestor module of the item whose visibility is being declared.pub(crate)
makes an item visible within the current crate.pub(super)
makes an item visible to the parent module. This is equivalent to pub(in super)
.pub(self)
makes an item visible to the current module. This is equivalent to pub(in self)
or not using pub
at all.
]]>
]]>
(閲戝簡鐨勪笓鏍?2021.7)
How to do multiple actions on Event BeginPlay in UE4 Blueprints?
Sams-Teach-Yourself-Unreal-Engine-4-Game-Development-in-24-Hours says:
```
Q. When I try to add a second event node, BeginPlay, the Editor shows me the first one already
placed in the Event Graph. Why does this happen?
A. Some events, such as Event Tick and the BeginPlay event, can have only one instance per
Blueprint.
```
https://forums.unrealengine.com/t/do-multiple-things-on-event-begin-play/411/10
```
The Sequence node allows for a single execution pulse to trigger a series of events in order. The node may have any number of outputs, all of which get called as soon as the Sequence node receives an input. They will always get called in order, but without any delay. To a typical user, the outputs will likely appear to have been triggered simultaneously.
```
Youtube video: [How to do Multiple Actions on Event Begin Play Unreal Engine 4 Blueprints](https://www.youtube.com/watch?v=nqG-ztbs230)
]]>
鍘熸枃錛歔Ninth generation of video game consoles](https://en.wikipedia.org/wiki/Ninth_generation_of_video_game_consoles)
2020.11錛屽井杞?MS) Xbox Series X/S 鍜?Sony PlayStation 5 (PS5) 鍙戝竷錛屾爣蹇楃潃娓告垙涓繪満榪涘叆絎?浠c?br />
鍜屽墠浠g殑 Xbox One 鍜?PS4 鐩告瘮錛屾柊涓浠d富鏈烘湁鍙鐨勬ц兘鎻愬崌錛屾敮鎸佸疄鏃跺厜綰胯窡韙紝4K鍒嗚鯨鐜囷紝鐩爣甯х巼涓?0銆?br />鍐呴儴閮戒嬌鐢ㄤ簡鍥烘佺‖鐩?SSD)銆備綆閰嶇増娌℃湁鍏夐┍錛屼粎鏀寔緗戠粶鍜孶SB銆?br />
瀹氫綅涓婅鑳滆繃浠誨ぉ鍫係witch鍜屼簯娓告垙鏈嶅姟濡?Stadia 鍜?Amazon Luna.
## 鑳屾櫙
絎?浠f椂闂磋緝闀褲傚洜涓烘懇灝斿畾寰嬶紝榪囧幓鍑犱唬涓鑸瘡浠d負5騫存椂闂達紝浣嗘槸 MS 鍜?Sony 鍑轟簡涓棿浠d駭鍝?Xbox One X 鍜?PS4 Pro.
2020.3 寮濮嬬殑 COVID-19 鐤儏褰卞搷涔熶嬌鏂頒竴浠d富鏈虹殑鍙戝竷寤跺悗浜嗐?br />
## 涓昏涓繪満
### PS5
鏈?涓満鍨嬶紝鍩烘湰鍨嬪拰鏁板瓧鍨嬶紝鏁板瓧鍨嬫病鏈夊厜椹辮緝渚垮疁錛屽叾浠栦竴鏍楓?br />PS5鍜孭S4鐨勬父鎴忓吋瀹癸紝鍙湁灝戦噺娓告垙涓嶆敮鎸侊紝浣嗘槸鍙互閫氳繃 PS Now 浜戞父鎴忔湇鍔$帺 PS4 娓告垙銆?br />
### Xbox Series X/S
MS 寤剁戶浜嗗弻涓繪満妯″紡錛氶珮绔殑X緋誨垪鍜屼綆绔殑S緋誨垪銆係緋誨垪娌℃湁鍏夐┍銆?br />涓よ呴兘鏀寔澶栭儴瀛樺偍鍜孹box Live鍦ㄧ嚎鍒嗗彂銆傚悜鍚庡吋瀹逛互鍓嶇殑娓告垙錛屼絾涓嶅寘鎷琄inect娓告垙銆?br />MS榧撳姳寮鍙戝晢浣跨敤 Smart Delivery錛屾妸Xbox One娓告垙鍗囩駭鍒癤box Series X/S銆?br />
## 鍏朵粬涓繪満
* 浠誨ぉ鍫?Switch
* 浜戞父鎴忓鉤鍙幫細Stadia, Amazon Luna, GeForce Now
]]>
(閲戝簡鐨勪笓鏍?2021.2)
濡傛灉寮傛(async鍏抽敭瀛?鏂規硶鏈夎繑鍥炲鹼紝榪斿洖綾誨瀷涓篢鏃訛紝榪斿洖綾誨瀷蹇呯劧鏄?`Task<T>`銆?br />浣嗘槸濡傛灉娌℃湁榪斿洖鍊鹼紝寮傛鏂規硶鐨勮繑鍥炵被鍨嬫湁2縐嶏紝涓涓槸榪斿洖 Task, 涓涓槸榪斿洖 void錛?br />```
public async Task CountDownAsync(int count)
{
for (int i = count; i >= 0; i--)
{
await Task.Delay(1000);
}
}
public async void CountDown(int count)
{
for (int i = count; i >= 0; i--)
{
await Task.Delay(1000);
}
}
```
璋冪敤鏃訛紝濡傛灉榪斿洖 Task, 浣嗚繑鍥炲艱蹇界暐鏃訛紝VS 浼氱敤緇胯壊娉㈡氮綰胯鍛婏細
```
CountDownAsync(3);
~~~~~~~~~~~~~~~~~
```
淇℃伅涓猴細
```
(awaitable) Task AsyncExample.CountDownAsync(int count)
Usage:
await CountDownAsync(...);
Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
```
涓枃涓猴細
```
CS4014:鐢變簬姝よ皟鐢ㄤ笉浼氱瓑寰咃紝鍥犳鍦ㄦ璋冪敤瀹屾垚涔嬪墠灝嗕細緇х畫鎵ц褰撳墠鏂規硶銆傝鑰冭檻灝?await"榪愮畻絎﹀簲鐢ㄤ簬璋冪敤緇撴灉銆?br />```
娣誨姞 await 鍚庡氨姝e父浜嗭細
```
await CountDownAsync(3);
```
濡傛灉璋冪敤鑰呬笉鏄竴涓紓姝ユ柟娉曪紝鍥犱負鍙湁鍦ㄥ紓姝ユ柟娉曚腑鎵嶅彲浠ヤ嬌鐢?await,
鎴栬呭茍涓嶆兂鍦ㄦ絳夊緟錛屽鎯沖悓鏃舵墽琛屽涓?CountDownAsync(),
灝變笉鑳藉簲鐢?await 鏉ユ秷闄よ鍛娿?br />
姝ゆ椂鍙互鏀圭敤 void 榪斿洖鍊肩殑鐗堟湰錛?br />```
void Test()
{
...
CountDown(3);
CountDown(3);
...
}
async void CountDown(int count)
{
for (int i = count; i >= 0; i--)
{
await Task.Delay(1000);
}
}
```
> Never call `async Task` methods without also awaiting on the returned Task. If you don’t want to wait for the async behaviour to complete, you should call an `async void` method instead.
鎽樿嚜錛歨ttp://www.stevevermeulen.com/index.php/2017/09/using-async-await-in-unity3d-2017/
CountDown() 鍙互鐩存帴璋冪敤 CountDownAsync() 瀹炵幇錛?br />```
async void CountDown(int count)
{
await CountDownAsync(count);
}
```
浣跨敤涓嬪垝綰垮彉閲忓拷鐣ュ紓姝ユ柟娉曠殑榪斿洖鍊間篃鍙互娑堥櫎璀﹀憡錛?br />```
void Test()
{
...
_ = CountDownAsync(3);
_ = CountDownAsync(3);
...
}
```
浣嗘槸榪欐牱鍚屾椂涔熶細蹇界暐 CountDownAsync() 涓殑寮傚父銆傚浠ヤ笅寮傚父浼氳蹇界暐銆?br />
```
void Test()
{
...
_ = CountDownAsync(3);
...
}
async Task CountDownAsync(int count)
{
for (int i = count; i >= 0; i--)
{
await Task.Delay(1000);
}
throw new Exception();
}
```
濡傛灉鏄皟鐢ㄨ繑鍥?void 鐨勫紓姝ユ柟娉曪紝Unity 浼氭姤閿欙細
```
Exception: Exception of type 'System.Exception' was thrown.
```
## 瀵?Async 鍚庣紑鐨勮鏄?br />
```
You could say that the Async suffix convention is to communicate to the API user that the method is awaitable. For a method to be awaitable, it must return Task for a void, or Task<T> for a value-returning method, which means only the latter can be suffixed with Async.
```
鎽樿嚜錛歨ttps://stackoverflow.com/questions/15951774
grpc 鐢熸垚鐨勪唬鐮佷腑錛屽紓姝ヨ姹傝繑鍥炰簡涓涓?AsyncCall 瀵硅薄錛孉syncCall 瀹炵幇浜?GetAwaiter() 鎺ュ彛錛?br />```
public virtual grpc::AsyncUnaryCall<global::Routeguide.Feature> GetFeatureAsync(global::Routeguide.Point request, ...)
```
鍙互榪欐牱璋冪敤騫剁瓑寰咃細
```
var resp = await client.GetFeatureAsync(req);
```
铏界劧榪斿洖綾誨瀷涓嶆槸`Task<>`, 浣嗘槸鍙瓑寰咃紝鎵浠ユ坊鍔犱簡 Async 鍚庣紑銆?br />
]]>
(閲戝簡鐨勪笓鏍?2020.9)
浠婂ぉ鍙戠幇涓渚?RPC 鍥炶皟姝婚攣錛岀幇璞′負涓涓茬浉鍏崇殑 RPC 璋冪敤鍏ㄩ儴瓚呮椂澶辮觸銆?br />
A 璋冪敤 B 鐨?RPC, B 鍐嶅洖璋?A, 褰㈡垚涓涓?RPC 璋冪敤鐜悗錛?br />濡傛灉 A 璋冪敤 B 鏃跺厛鍔犱簡涓涓攣錛岀劧鍚?B 鍥炶皟 A 鏃跺張闇瑕佽繖涓攣錛?br />鑰屾鏃?A 姝e湪絳夊緟 B 鐨?RPC 榪斿洖錛屼箣鍚庢墠浼氶噴鏀鵑攣錛?br />榪欐牱灝卞艦鎴愪簡姝婚攣銆傝繖涓?RPC 璋冪敤鐜渶緇堜細鍏ㄩ儴瓚呮椂澶辮觸銆?br />
榪欎釜璋冪敤鐜彲鑳戒細娑夊強澶氫釜鏈嶅姟錛屽 A->B->C->...->A銆?br />
閬垮厤鍥炶皟姝婚攣鏈変互涓嬫柟娉曘?br />
## 閬垮厤鍥炶皟錛屼笉瑕佹湁 RPC 璋冪敤鐜?br />
涓鑸殑鏈嶅姟渚濊禆搴旇閮芥槸鏃犵幆鐨勩?br />鍙互鐢諱竴涓湇鍔′緷璧栧浘錛屽鏋滄病鏈夊艦鎴愯皟鐢ㄧ幆錛屽氨鍙互鏀懼績涓嶄細鏈夋閿併?br />
## RPC 璋冪敤鏃朵笉瑕佸姞閿?br />
涓鑸繘鍏ユ煇涓?RPC 澶勭悊鏃訛紝浼氶攣浣忕浉鍏崇殑璧勬簮錛岀洿鍒板鐞嗗畬鎴愩?br />濡傛灉澶勭悊榪囩▼涓渶瑕佸悜澶栧彂鍑?RPC 璇鋒眰錛屽簲璇ュ厛閲婃斁閿侊紝寰呰姹傚畬鎴愬悗鍐嶆鑾峰彇閿併?br />濡傛灉璇鋒眰榪囩▼涓渶瑕佺姝㈠叾浠栧崗紼嬫搷浣滅浉鍏寵祫婧愶紝涔熷彲浠ヤ笉閲婃斁閿侊紝
浣嗛攣鐨勪嬌鐢ㄤ笂搴旇鍏佽鍔犻攣澶辮觸錛屼笉瑕佺瓑寰呴攣銆?br />
閿佸簲璇ユ槸鑳藉蹇熼噴鏀劇殑銆傚鏋滈渶瑕佸姞閿佸幓鎵ц涓涓暱鏃墮棿鐨勬搷浣滐紝
榪欎釜閿佺殑璁捐鍙兘闇瑕侀噸鏂拌冭檻銆?br />
## 鎵撴柇璋冪敤閾?br />
鏈夋椂鍊?RPC 璋冪敤閾句笉蹇呮槸闃誨絳夊緟鐨勩?br />濡傞氱煡鎬х殑錛屾棤榪斿洖鍊肩殑RPC, 涓嶉渶瑕佺瓑寰呬粬榪斿洖錛屽彲浠ュ紑涓涓柊鐨勫崗紼嬪幓鎵ц RPC.
鐖禦PC絳夊緟瀛怰PC榪斿洖錛屾敼涓虹埗RPC鐩存帴榪斿洖錛屽瓙RPC鍚庡彴鎵ц錛屽嵆鏂紑 RPC 鐨勮皟鐢ㄤ緷璧栥?br />RPC 璋冪敤閾炬柇寮鎴愬孌靛悗錛岃皟鐢ㄥ驚鐜殑鍙兘鎬у氨澶уぇ涓嬮檷浜嗐?br />
]]>
(閲戝簡鐨勪笓鏍?2020.8)
lua涓笉鍖哄垎 string 鍜?byte[], 鑰屽湪 C# 涓?string 鍜?byte[] 涔嬮棿杞崲娑夊強緙栫爜銆?br />
C# 涓竴鑸繖鏍瘋漿錛?br />
string綾誨瀷杞垚byte[]錛?br />```
byte[] byteArray = System.Text.Encoding.Default.GetBytes(str);
```
byte[]杞垚string錛?br />```
string str = System.Text.Encoding.Default.GetString(byteArray);
```
Default 緙栫爜鏄湰鏈哄綋鍓嶆墍鐢ㄧ紪鐮侊紝榪樺彲浠ョ敤 ASCII, UTF8 絳夊叾浠栫紪鐮併?br />
嫻嬩簡鍦?lua 涓鍏ヤ竴鍧?榪涘埗鏁版嵁錛岃皟鐢?tolua 瀵煎嚭鐨勪竴涓柟娉曪紝濡傦細
```
public void Print(string s)
{
byte[] buf = Systen.Text.Encoding.Default.GetBytes(s);
Debug.Log(Bitconvert.ToString(buf));
}
```
嫻嬩簡 Default, ASCII, UTF8, ISO-8859-1(Latin-1), Unicode 鍙戠幇寰楀埌鐨?byte[] 浼氬嚭閿欍?br />
涔熻瘯浜?[C#涓嬌鐢˙uffer.BlockCopy()鏂規硶灝唖tring杞崲涓篵yte array鐨勬柟娉昡(https://www.cnblogs.com/ChineseMoonGod/p/5689526.html)
鍙戠幇 tolua 浼犲埌 C# 鐨?string 宸茬粡鏄紪鐮佽繃鐨勶紝鐩存帴澶嶅埗涔熸槸閿欑殑銆?br />
xlua 涔熸湁鐩稿悓闂錛孾Unity xlua 浠巐ua浼犻抌yte[]鏁版嵁鍒癈#](https://www.jianshu.com/p/63987134c1ba)
浣跨敤 MemoryStream瀵硅薄鏉ヤ紶閫抌yte[]鏁版嵁錛岀‘瀹炴湁鐐圭粫銆?br />
tolua 涓湁涓?LuaByteBuffer錛屽彲浠ョ敤鏉ヤ紶閫?byte[].
[tolua#涓殑LuaByteBuffer綾籡(http://bbs.ulua.org/article/ulua/toluazhongdeluabytebufferlei.html)
浠?lua 浼?byte[] 鍒?C#, 鍙渶瑕佸皢鍙傛暟 string 鏀逛負 LuaByteBuffer:
```
public void Print(LuaByteBuffer luaByteBuffer)
{
byte[] buf = luaByteBuffer.buffer;
Debug.Log(Bitconvert.ToString(buf));
}
```
鏇存紜張綆鍗曠殑鏂規硶鏄敤 LuaByteBufferAttribute:
```
[LuaByteBufferAttribute]
public void Print(byte[] buf)
{
Debug.Log(Bitconvert.ToString(buf));
}
```
鏈緇堝彂鐜頒笉闇瑕?LuaByteBufferAttribute錛岀洿鎺ョ敤 byte[] 灝辮錛?br />```
public void Print(byte[] buf)
{
Debug.Log(Bitconvert.ToString(buf));
}
```
C# 浼?byte[] 鍒?lua, 榛樿涓?"System.Byte[]"(userdata)錛屽彲浠ョ敤 tostring() 杞負 lua string:
```Lua
s = tolua.tolstring(result)
```
濡傛灉鍙互錛屽簲璇ョ粰鏁版嵁鍔犱笂鏍囩[LuaByteBufferAttribute]錛岃繖鏍蜂紶鍒?lua 灝辨槸 string銆?br />鎴栬呭湪C#寤轟竴涓狶uaByteBuffer鎶奲yte[]浼犵粰lua銆?br />
]]>
(閲戝簡鐨勪笓鏍?2020.6)
Unity 淇濊瘉 async 鏂規硶榪愯鍦ㄤ富綰跨▼涓紝鎵浠ョ敤寮傛鏂瑰紡璋冪敤 grpc 鍙互澶уぇ綆鍖栫綉緇滈氫俊鐨勪唬鐮併?br />
浠ヤ笅紺轟緥涓皢 grpc 鐨?RouteGuide 紺轟緥縐誨埌 Unity 涓繍琛屻?br />https://github.com/grpc/grpc/tree/master/examples/csharp/RouteGuide
鍏朵腑 Main() 涓殑浠g爜縐誨埌 Start() 涓繍琛岋紝闃誨璋冪敤鏀規垚寮傛璋冪敤, GetFeature() 鏀規垚 GetFeatureAsync()銆?br />
瀹屾暣浠g爜瑙侊細https://gitee.com/jinq0123/unity-grpc-async
```
using Grpc.Core;
using Routeguide;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static Routeguide.Program;
public class Test : MonoBehaviour
{
// Start is called before the first frame update
async void Start()
{
var channel = new Channel("127.0.0.1:50052", ChannelCredentials.Insecure);
var client = new RouteGuideClient(new RouteGuide.RouteGuideClient(channel));
// Looking for a valid feature
await client.GetFeatureAsync(409146138, -746188906);
// Feature missing.
await client.GetFeatureAsync(0, 0);
// Looking for features between 40, -75 and 42, -73.
await client.ListFeatures(400000000, -750000000, 420000000, -730000000);
// Record a few randomly selected points from the features file.
await client.RecordRoute(RouteGuideUtil.LoadFeatures(), 10);
// Send and receive some notes.
await client.RouteChat();
await channel.ShutdownAsync();
Debug.Log("End of test.");
}
}
```
]]>
(閲戝簡鐨勪笓鏍?2019.9)
svn rename 鏌愪釜鏂囦歡騫舵洿鏀瑰唴瀹瑰悗鎻愪氦錛屽巻鍙插氨浼氫涪澶便?br />濡傛灉 svn rename 鍚庝笉鏀瑰唴瀹癸紝绔嬪嵆鎻愪氦錛屽氨鍙互寤剁畫鍘熸湁鍘嗗彶銆?br />鎵浠ユ敼鍚嶈繖鏍風殑鎿嶄綔搴旇鐙珛鎻愪氦涓嬈°?br />
git 鏀瑰悕灝卞己澶у浜嗭紝浼氭瘮杈冨唴瀹圭‘瀹氬叾鍘熸潵鐨勬枃浠躲備絾鏇存敼澶涔熶細鍒ゆ柇鍑洪敊銆?br />
]]>
(閲戝簡鐨勪笓鏍?2018.11)
浠庡畼緗戜笅杞戒簡 vs_community__1600125377.1541561546.exe錛屼絾鏄繍琛屽畨瑁呮椂鏃犳硶鍑虹幇浜у搧閫夋嫨鐣岄潰銆?br />
鏌ョ湅 Temp 鐩綍涓嬬殑鏃ュ織錛屾病鏈夊彂鐜伴敊璇?br />
鎼滅儲涓涓嬶紝鍙戠幇鏈夊ぇ閲忕殑鍚岀被閿欒錛?br />
* VS : How to fix stuck Visual Studio Community installation problem
https://www.howtosolutions.net/2015/08/solving-installation-is-stuck-problem-in-visual-studio-community-edition/
* Resolving Installation Issues with Visual Studio 2017
http://rion.io/2017/02/17/resolving-installation-issues-with-visual-studio-2017/
* Unable to start vs_installer.exe to install VS2017 Community
https://social.msdn.microsoft.com/Forums/vstudio/en-US/fc8f5a04-8687-48dd-987e-1cfac67566a1/unable-to-start-vsinstallerexe-to-install-vs2017-community?forum=vssetup
* VS 2017 Installer quits before starting
https://developercommunity.visualstudio.com/content/problem/8993/vs-2017-installer-quits-before-starting.html
* VS2017鏃犳硶榪涘叆瀹夎鐣岄潰闂鐨勮В鍐蟲柟娉?- 鍘氱Н钖勫彂錛屾寔涔嬩互鎭?- CSDN鍗氬
https://blog.csdn.net/qq951127336/article/details/71036868
* VS2017瀹夎鏃惰嚜鍔ㄩ鍑篲yanggy_鏂版氮鍗氬
http://blog.sina.com.cn/s/blog_702b606a0102y6n3.html
浣嗘槸閮芥病鏈夌敤銆?br />
浠庝互涓婃柟妗堜腑浜嗚В鍒幫紝`C:\Program Files (x86)\Microsoft Visual Studio\Installer`鍙兘瀛樺湪鍧忔枃浠訛紝鎵浠ユ棤娉曞畨瑁呫?br />浣嗘槸娓呯悊涔嬪悗閲嶆柊涓嬭澆錛屼粛鐒舵槸鍚屾牱鎯呭喌銆?br />
璇曠潃榪愯浜嗗叾涓殑 vs_installer.exe錛屽脊鍑虹晫闈㈣鏈夊吋瀹規ч敊璇紝鍙互閫夋嫨淇銆?br />淇涔嬪悗錛寁s_installer.exe 灝卞嚭鐜頒駭鍝侀夋嫨鐣岄潰浜嗐?br />
鐒跺悗鍐嶈繍琛?vs_community__1600125377.1541561546.exe錛屽氨鍙互鍑虹幇浜у搧閫夋嫨鐣岄潰浜嗐?br />
闂鍙兘鏄繖涓?Installer 瀹夎涓嶅錛屽彲鑳芥槸閫夋嫨浜嗛敊璇殑鐗堟湰錛屽垹闄ゅ悗閲嶆柊涓嬭澆榪樻槸涓鏍鳳紝榪樺ソ鍙互鎵嬪姩淇涓涓嬨?br />
鐜板湪姝e湪瀹夎 vs2017.
]]>
(閲戝簡鐨勪笓鏍?2018.9)
Dockerfile.frontendapi 涓湁 `RUN go get`, 闇瑕佽緗唬鐞嗐?br />
docker build . -f Dockerfile.frontendapi \
-t registry.cn-shanghai.aliyuncs.com/jinq0123/openmatch-frontendapi:dev \
--network host \
--build-arg HTTP_PROXY=http://127.0.0.1:1080 \
--build-arg HTTPS_PROXY=http://127.0.0.1:1080
鍥犱負 docker build 浼氬湪涓涓鍣ㄥ唴鎵ц錛屾墍浠ラ』鎸囧畾 network 涓?host, 浣夸箣鍙互榪炴帴鏈満鐨勪唬鐞嗐?br />
鍙傝冿細
https://stackoverflow.com/questions/22179301/how-do-you-run-apt-get-in-a-dockerfile-behind-a-proxy
[root@pppdc9prda2y java]# docker build
--build-arg https_proxy=$HTTP_PROXY --build-arg http_proxy=$HTTP_PROXY
--build-arg HTTP_PROXY=$HTTP_PROXY --build-arg HTTPS_PROXY=$HTTP_PROXY
--build-arg NO_PROXY=$NO_PROXY --build-arg no_proxy=$NO_PROXY -t java .
]]>
(閲戝簡鐨勪笓鏍?2018.7)
緗戞父鏈嶅姟鍣ㄤ腑鐨勬埧闂存湇鍔″櫒鏄湁鐘舵佹湇鍔″櫒錛屽彲浠ョ敤 kubernetes statefulset 寮鍚涓疄渚嬨?br />
涓轟簡璁╁鎴風鑳藉鐩磋繛鎴塊棿鏈嶅姟鍣紝闄や簡 statefulset 瑕佹眰鐨?headless 鏈嶅姟錛?br />榪橀』涓烘瘡涓疄渚嬪垱寤?NodePort 綾誨瀷鐨勬湇鍔? 騫朵笖閫夋嫨Pod鍜岀姝㈣漿鍙戙?br />
涓嬮潰 bootcamp.yml 鍏堝垱寤轟簡 bootcamp headless 鏈嶅姟(clusterIP: None),
鍙堝垱寤轟簡 bootcamp StatefulSet, 瀹炰緥涓暟涓?2.
鐒跺悗鍒涘緩 bootcamp-0,1,2 鏈嶅姟錛屽垎鍒搴?bootcamp-0,1,2 pod.
鏈嶅姟涓暟澶т簬瀹炰緥涓暟錛屾槸鎯蟲祴璇曚笅鏈嶅姟娌℃湁瀵瑰簲鐨勫疄渚嬫椂鐨勮〃鐜般?br />
緗戞父涓殑鍖歸厤鏈嶅姟鍣ㄥ皢鍒嗛厤涓涓埧闂寸粰瀹㈡埛绔紝鍒椾婦 bootcamp-0,1,2 pod 鎵鍦ㄨ妭鐐圭殑澶栫綉 IP,
榪炲悓瀵瑰簲鏈嶅姟鐨勭鍙o紝鍙戦佺粰瀹㈡埛绔紝璁╁鎴風鐩磋繛銆?br />
[jinqing@host-10-240-79-10 statefulset]$ cat bootcamp.yml
apiVersion: v1
kind: Service
metadata:
name: bootcamp
namespace: jq
labels:
name: bootcamp
spec:
ports:
- port: 8080
clusterIP: None # StatefulSet瑕佹眰Headless鏈嶅姟
selector:
app: bootcamp # 閫夋嫨 bootcamp 搴旂敤
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: bootcamp
namespace: jq
spec:
serviceName: bootcamp # 涓婇潰鐨?Headless 鏈嶅姟鍚?/span>
replicas: 2
template:
metadata:
labels:
app: bootcamp # 搴旂敤鍚嶏紝涓庢湇鍔′腑鐨?selector 瀵瑰簲
spec:
containers:
- name: bootcamp
image: docker.io/jocatalin/kubernetes-bootcamp:v1
---
kind: Service
apiVersion: v1
metadata:
name: bootcamp-0
namespace: jq
spec:
type: NodePort # 瀵瑰鏈嶅姟
externalTrafficPolicy: Local # 涓嶈杞彂鍒板叾浠栬妭鐐?/span>
selector:
app: bootcamp
statefulset.kubernetes.io/pod-name: bootcamp-0 # 閫夋嫨 pod
ports:
- protocol: TCP
nodePort: 30880 # 瀵瑰绔彛
port: 8080
---
kind: Service
apiVersion: v1
metadata:
name: bootcamp-1
namespace: jq
spec:
type: NodePort
externalTrafficPolicy: Local
selector:
app: bootcamp
statefulset.kubernetes.io/pod-name: bootcamp-1
ports:
- protocol: TCP
nodePort: 30881
port: 8080
---
kind: Service
apiVersion: v1
metadata:
name: bootcamp-2
namespace: jq
spec:
type: NodePort
externalTrafficPolicy: Local
selector:
app: bootcamp
statefulset.kubernetes.io/pod-name: bootcamp-2
ports:
- protocol: TCP
nodePort: 30882
port: 8080
鍥犱負 statefulset 鐨勬瘡涓疄渚嬫湁涓嶅悓鐨勬爣絳撅紝鎵浠ュ彲浠ヤ負鏈嶅姟閫夋嫨涓涓疄渚嬨?br />
鍒╃敤 externalTrafficPolicy: Local 璁劇疆鏉ョ姝㈣漿鍙戙?br />鍙傝?service.spec.externalTrafficPolicy 鐨勮鏄庯細
https://kubernetes.io/docs/tutorials/services/source-ip/#source-ip-for-services-with-type-nodeport
Setting service.spec.externalTrafficPolicy to the value Local will only proxy requests to local endpoints, never forwarding traffic to other nodes and thereby preserving the original source IP address. If there are no local endpoints, packets sent to the node are dropped, ...
鍥犱負鏈夊彲鑳藉涓狿od寮鍦ㄥ悓涓鑺傜偣涓婏紝鎵浠ュ澶栫鍙h鎴愪簡涓嶅悓鐨?30880-30882銆?br />濡傛灉闄愬埗姣忎釜鑺傜偣鍙紑涓涓疄渚嬶紝鍒欏澶栫鍙e彲浠ヨ鎴愬悓涓涓?br />
鍒涘緩鏈嶅姟錛?br />
[jinqing@host-10-240-79-10 statefulset]$ kubectl apply -f bootcamp.yml
service "bootcamp" created
statefulset.apps "bootcamp" created
service "bootcamp-0" created
service "bootcamp-1" created
service "bootcamp-2" created
鏈嶅姟濡備笅錛?br />
[jinqing@host-10-240-79-10 statefulset]$ kubectl get service -n jq
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
bootcamp ClusterIP None <none> 8080/TCP 3m
bootcamp-0 NodePort 10.96.128.137 <none> 8080:30880/TCP 3m
bootcamp-1 NodePort 10.109.2.56 <none> 8080:30881/TCP 3m
bootcamp-2 NodePort 10.102.181.193 <none> 8080:30882/TCP 3m
2涓疄渚嬶細
[jinqing@host-10-240-79-10 statefulset]$ kubectl get pod -n jq -o wide
NAME READY STATUS RESTARTS AGE IP NODE
bootcamp-0 1/1 Running 0 4m 10.244.0.42 host-10-240-79-10
bootcamp-1 1/1 Running 0 4m 10.244.1.63 host-10-240-79-11
璁塊棶鏈嶅姟蹇呴』鎸囧畾鑺傜偣錛屼笉浼氳嚜鍔ㄨ漿鍙戯細
[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.10:30880
Hello Kubernetes bootcamp! | Running on: bootcamp-0 | v=1
[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.10:30881
curl: (7) Failed connect to 10.240.79.10:30881; Connection timed out
[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.11:30880
curl: (7) Failed connect to 10.240.79.11:30880; Connection timed out
[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.11:30881
Hello Kubernetes bootcamp! | Running on: bootcamp-1 | v=1
娌℃湁璐熻澆鍧囪 錛?0881绔彛鎬繪槸璁塊棶 bootcamp-1錛?br />
[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.11:30881
Hello Kubernetes bootcamp! | Running on: bootcamp-1 | v=1
[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.11:30881
Hello Kubernetes bootcamp! | Running on: bootcamp-1 | v=1
[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.11:30881
Hello Kubernetes bootcamp! | Running on: bootcamp-1 | v=1
[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.11:30881
Hello Kubernetes bootcamp! | Running on: bootcamp-1 | v=1
[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.11:30881
Hello Kubernetes bootcamp! | Running on: bootcamp-1 | v=1
涔熷彲浠ヤ粠澶栫綉璁塊棶.
30882 绔彛鏃犳硶榪炴帴錛?br />
[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.11:30882
curl: (7) Failed connect to 10.240.79.11:30882; Connection refused
[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.10:30882
curl: (7) Failed connect to 10.240.79.10:30882; Connection refused
3涓鍙i兘鏈夌洃鍚細
[root@host-10-240-79-11 tmp]# netstat -ntl | grep 3088
tcp6 0 0 :::30881 :::* LISTEN
tcp6 0 0 :::30882 :::* LISTEN
tcp6 0 0 :::30880 :::* LISTEN
iptables-save 杈撳嚭濡備笅, 鍏朵腑 10.244鏄疨od鐨勭綉孌點?br />
娌℃湁瀹炰緥榪愯鐨勮妭鐐逛笂錛屼細涓㈠純璇鋒眰錛?br />
-A KUBE-NODEPORTS -s 127.0.0.0/8 -p tcp -m comment --comment "jq/bootcamp-1:" -m tcp --dport 30881 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "jq/bootcamp-1:" -m tcp --dport 30881 -j KUBE-XLB-LJXDQ4W47M42IZBH
-A KUBE-NODEPORTS -s 127.0.0.0/8 -p tcp -m comment --comment "jq/bootcamp-0:" -m tcp --dport 30880 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "jq/bootcamp-0:" -m tcp --dport 30880 -j KUBE-XLB-U5NEOQT6R5WSBVOH
-A KUBE-XLB-LJXDQ4W47M42IZBH -s 10.244.0.0/16 -m comment --comment "Redirect pods trying to reach external loadbalancer VIP to clusterIP" -j KUBE-SVC-LJXDQ4W47M42IZBH
-A KUBE-XLB-LJXDQ4W47M42IZBH -m comment --comment "jq/bootcamp-1: has no local endpoints" -j KUBE-MARK-DROP
-A KUBE-XLB-U5NEOQT6R5WSBVOH -s 10.244.0.0/16 -m comment --comment "Redirect pods trying to reach external loadbalancer VIP to clusterIP" -j KUBE-SVC-U5NEOQT6R5WSBVOH
-A KUBE-XLB-U5NEOQT6R5WSBVOH -m comment --comment "jq/bootcamp-0: has no local endpoints" -j KUBE-MARK-DROP
鏈夊疄渚嬭繍琛岀殑鑺傜偣涓婁細杞彂緇?Pod 8080錛?br />
-A KUBE-NODEPORTS -s 127.0.0.0/8 -p tcp -m comment --comment "jq/bootcamp-0:" -m tcp --dport 30880 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "jq/bootcamp-0:" -m tcp --dport 30880 -j KUBE-XLB-U5NEOQT6R5WSBVOH
-A KUBE-NODEPORTS -s 127.0.0.0/8 -p tcp -m comment --comment "jq/bootcamp-1:" -m tcp --dport 30881 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "jq/bootcamp-1:" -m tcp --dport 30881 -j KUBE-XLB-LJXDQ4W47M42IZBH
-A KUBE-XLB-LJXDQ4W47M42IZBH -s 10.244.0.0/16 -m comment --comment "Redirect pods trying to reach external loadbalancer VIP to clusterIP" -j KUBE-SVC-LJXDQ4W47M42IZBH
-A KUBE-XLB-LJXDQ4W47M42IZBH -m comment --comment "Balancing rule 0 for jq/bootcamp-1:" -j KUBE-SEP-LJQA4WUIKJUQ5ALU
-A KUBE-XLB-U5NEOQT6R5WSBVOH -s 10.244.0.0/16 -m comment --comment "Redirect pods trying to reach external loadbalancer VIP to clusterIP" -j KUBE-SVC-U5NEOQT6R5WSBVOH
-A KUBE-XLB-U5NEOQT6R5WSBVOH -m comment --comment "jq/bootcamp-0: has no local endpoints" -j KUBE-MARK-DROP
-A KUBE-SEP-LJQA4WUIKJUQ5ALU -s 10.244.1.63/32 -m comment --comment "jq/bootcamp-1:" -j KUBE-MARK-MASQ
-A KUBE-SEP-LJQA4WUIKJUQ5ALU -p tcp -m comment --comment "jq/bootcamp-1:" -m tcp -j DNAT --to-destination 10.244.1.63:8080
30882 绔彛鏃犳硶榪炴帴
-A KUBE-EXTERNAL-SERVICES -p tcp -m comment --comment "jq/bootcamp-2: has no endpoints" -m addrtype --dst-type LOCAL -m tcp --dport 30882 -j REJECT --reject-with icmp-port-unreachable
嫻嬭瘯涓嬫墿瀹癸細
[jinqing@host-10-240-79-10 statefulset]$ kubectl get statefulset -n jq
NAME DESIRED CURRENT AGE
bootcamp 2 2 45m
[jinqing@host-10-240-79-10 statefulset]$ kubectl scale --replicas=3 statefulset/bootcamp -n jq
statefulset.apps "bootcamp" scaled
[jinqing@host-10-240-79-10 statefulset]$ kubectl get statefulset -n jq
NAME DESIRED CURRENT AGE
bootcamp 3 3 47m
[jinqing@host-10-240-79-10 statefulset]$ kubectl get pod -n jq -o wide
NAME READY STATUS RESTARTS AGE IP NODE
bootcamp-0 1/1 Running 0 48m 10.244.0.42 host-10-240-79-10
bootcamp-1 1/1 Running 0 48m 10.244.1.63 host-10-240-79-11
bootcamp-2 1/1 Running 0 45s 10.244.2.60 host-10-240-79-12
[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.12:30882
Hello Kubernetes bootcamp! | Running on: bootcamp-2 | v=1
]]>
(閲戝簡鐨勪笓鏍?2018.6)
grpc-go鏈嶅姟鍣ㄧ殑姣忎釜璇鋒眰閮藉湪涓涓嫭绔嬬殑鍗忕▼涓墽琛屻?br />緗戞父鏈嶅姟鍣ㄤ腑錛屼竴鑸姹備細璋冪敤娓告垙鎴塊棿鐨勬柟娉曪紝鑰屾埧闂存槸涓涓嫭绔嬬殑鍗忕▼銆?br />鍙互灝嗘埧闂村疄鐜頒負actor錛実rpc璇鋒眰閫氳繃Call()鎴朠ost()鏂規硶鏉ユ墽琛屻?br />鍏朵腑Call()浼氱瓑寰呰繑鍥烇紝鑰孭ost()浼氬紓姝ユ墽琛屾棤榪斿洖鍊箋?br />
type Room struct {
// actC 鏄叾浠栧崗紼嬪悜Room鍗忕▼鍙戦佸姩浣滅殑Channel錛屽崗紼嬩腑灝嗕緷嬈℃墽琛屽姩浣溿?/span>
// Action 鍔ㄤ綔, 鏄棤鍙傛暟鏃犺繑鍥炲肩殑鍑芥暟.
actC chan func()
...
}
// Run 榪愯鎴塊棿鍗忕▼.
func (r *Room) Run() {
ticker := time.NewTicker(20 * time.Millisecond)
defer ticker.Stop()
for r.running {
select {
case act := <-r.actC:
act()
case <-ticker.C:
r.tick()
}
}
}
// Call calls a function f and returns the result.
// f runs in the Room's goroutine.
func (r *Room) Call(f func() interface{}) interface{} {
// 緇撴灉浠巆h榪斿洖
ch := make(chan interface{}, 1)
r.actC <- func() {
ch <- f()
}
// 絳夊緟鐩村埌榪斿洖緇撴灉
return <-ch
}
// Post 灝嗕竴涓姩浣滄姇閫掑埌鍐呴儴鍗忕▼涓墽琛?
func (r *Room) Post(f func()) {
r.actC <- f
}
grpc鏈嶅姟鏂規硶濡傦細
func (m *RoomService) Test(ctx context.Context, req *pb.TestReq) (*pb.TestResp, error) {
conn := conn_mgr.GetConn(ctx)
if conn == nil {
return nil, fmt.Errorf("can not find connection")
}
room := conn.GetRoom()
resp := room.Call(func() interface{} {
return room.Test(req)
})
return resp.(*pb.TestResp), nil
}
]]>
(閲戝簡鐨勪笓鏍?2018.5)
https://github.com/aurelien-rainone/assertgo
Conditionally compiled assertions in Go
鍜孋++涓殑assert()涓鏍鳳紝榪欎釜鏄甫鏉′歡緙栬瘧鐨勶紝蹇呴』浣跨敤 debug 鎵嶈兘鍚敤銆?br />
濡傦細
$ go run -tags debug main.go
浣跨敤紺轟緥錛?br />
assert.True(true, "never printed")
]]>
(閲戝簡鐨勪笓鏍?2018.5)
consul鍛戒護琛屼腑鏈変互涓嬪嚑涓湴鍧鍙傛暟錛?br />
* -bind
緇戝畾鍦板潃錛岀敤浜庨泦緹ら氫俊錛岀己鐪?0.0.0.0
* -clint
緇戝畾鍦板潃錛岀敤浜?RPC, DNS, HTTP and HTTPS錛岀己鐪?127.0.0.1
* -serf-lan-bind
緇戝畾鍦板潃錛岀敤浜庡唴緗戦泦緹ら氫俊錛岀己鐪佷嬌鐢?-bind 鍦板潃
* -serf-wan-bind
緇戝畾鍦板潃錛岀敤浜庤法鏈烘埧閫氫俊錛岀己鐪佷嬌鐢?-bind 鍦板潃
* -advertise
閫氬憡鍦板潃錛岄氬憡緇欓泦緹や腑鍏朵粬鑺傜偣錛岀己鐪佷嬌鐢?-bind 鍦板潃
* -advertise-wan
閫氬憡鍦板潃錛岄氬憡緇欏叾浠栨満鎴跨殑鏈嶅姟鑺傜偣錛岀己鐪佷嬌鐢?-advertise 鍦板潃
* -join -retry-join
鍔犲叆闆嗙兢鐨勭洰鏍囧湴鍧
* -join-wan -retry-join-wan
璺ㄦ満鎴塊偊鑱旂殑鐩爣鍦板潃
* -recursor
涓婃父DNS鍦板潃
瀹樻柟鏂囨。錛?https://www.consul.io/docs/agent/options.html#command-line-options
]]>
]]>
(閲戝簡鐨勪笓鏍?2018.4)
grpc-lua (https://github.com/jinq0123/grpc-lua) 鏄?grpc 鐨?lua 緇戝畾搴擄紝
搴旂敤浜?luapbintf , 涓嶉渶瑕佺敓鎴愪唬鐮侊紝鐩存帴璇誨彇 proto 鏂囦歡銆?br />
濡傦細
-- Sync request.
local request = { name = "world" }
local response = assert(stub:sync_request("SayHello", request))
print("Greeter received: " .. response.message)
瀹屾暣鐨勭ず渚嬩唬鐮佽 examples 鐩綍銆?br />
鏈嶅姟鍣ㄥ拰瀹㈡埛绔兘鏀寔鍚屾鍜屽紓姝ヨ皟鐢ㄣ?br />
灝?examples/conan_install.bat.example 鍘婚櫎 .example 鍚庣紑錛岀劧鍚庤繍琛岋紝
灝嗗畨瑁呮墍鏈夌殑渚濊禆搴? 欏誨厛瀹夎 conan 鍖呯鐞嗗伐鍏?(http://docs.conan.io/en/latest/installation.html)銆?br />榪橀渶瑕佽緗?git 浠g悊錛屽洜涓?grpc 鐨勫瓙搴撻渶瑕佺炕榪濆銆?br />
conan_install.bat 瀹為檯涓婃槸涓嬭澆渚濊禆搴撲唬鐮佸茍緙栬瘧銆傜粨鏋滃湪鐢ㄦ埛鐩綍 .conan/data/銆?br />鍦ㄥ叾涓悳绱?lua-cpp.exe, lua-cpp.dll, luapbintf.dll, grpc_lua.dll 騫跺鍒跺埌 examples/helloworld/ 鐩綍涓嬨?br />
鐒跺悗鍦?helloworld 鐩綍涓嬪垎鍒繍琛?run_server.bat 鍜?run_client.bat 嫻嬭瘯銆?br />
grpc-lua 紺轟緥 CentOS 7.4 鎵ц紼嬪簭鎵撳寘錛歨ttps://download.csdn.net/download/jq0123/10346003
CentOS 7.4 瀹炴祴錛?br />
[jinqing@localhost helloworld]$ ls
greeter_client.lua grpc_lua.so lua-cpp run_server.bat
greeter_server.lua helloworld.proto luapbintf.so
greeter_service.lua liblua-cpp.so run_client.bat
[jinqing@localhost helloworld]$ ./lua-cpp greeter_server.lua
Server listening on 0.0.0.0:50051
Got hello from world
Got hello from world
[jinqing@localhost helloworld]$ ./lua-cpp greeter_client.lua
Greeter received: Hello world
Async greeter received: Hello world
[jinqing@localhost helloworld]$
[jinqing@localhost route_guide]$ ./lua-cpp route_guide_server.lua
RecordRoute reader end.
RouteChat reader end.
[jinqing@localhost route_guide]$ ./lua-cpp route_guide_client.lua
-------------- Sync get feature --------------
Found feature: {
...
]]>
(閲戝簡鐨勪笓鏍?2018.4)
浠ュ墠鐢?Notepad++ 鐨勫叏鏂囨悳绱紝娌℃湁绱㈠紩錛屾瘡嬈℃悳绱㈤兘欏葷瓑寰呬竴浼氬効銆?br />
鑰?DocFetcher 鏄紑婧愮殑妗岄潰鎼滅儲搴旂敤錛屽緩濂界儲寮曞悗錛屾悳绱細绔嬪嵆鍑虹粨鏋溿?br />
鍏堥』涓烘煇涓洰褰曞垱寤虹儲寮曪紝閫夋嫨鏌愪簺鍚庣紑鍚嶇殑鏂囦歡銆傜劧鍚庨変腑璇ョ儲寮曡繘琛屾悳绱€?br />
]]>
(閲戝簡鐨勪笓鏍?2017.12)
鎶?example greeter 鏀逛竴涓嬶紝澶勭悊 SayHello() 璇鋒眰鏃訛紝涓嶄粎浠呰繑鍥炴湰嬈¤姹傝呯殑鍚嶅瓧錛?br />榪樿繑鍥炰笂嬈¤姹傜殑鍚嶅瓧錛屽錛?br />```
λ go run greeter_client/main.go
2017/12/25 17:59:13 Greeting: Hello 'world' (prev '')
2017/12/25 17:59:15 Greeting: Hello 'world2' (prev 'world')
```
鍏堝皢瀹㈡埛绔崟嬈¤姹傛敼涓哄嬈¤姹傦細
```go
r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})
log.Printf("Greeting: %s", r.Message)
time.Sleep(2 * time.Second)
r, err = c.SayHello(context.Background(), &pb.HelloRequest{Name: name + "2"})
log.Printf("Greeting: %s", r.Message)
...
```
鏈嶅姟鍣ㄩ渶瑕佷負姣忎釜榪炴帴淇濆瓨鍚勮嚜鐨勬暟鎹傝繛鎺ュ垱寤烘椂鍒濆鍖栨暟鎹紝榪炴帴鏂紑鏃舵竻鐞嗘暟鎹?br />榪欓噷鍒╃敤浜嗚繛鎺ョ粺璁$殑鎺ュ彛錛屼笉鐭ラ亾鏄惁鏄渶閫傚綋鐨勫疄鐜版柟寮?
鏈嶅姟鍣ㄥ垱寤烘椂娣誨姞 StatsHandler 閫夐」錛岃緭鍏ヤ竴涓?stats.Handler 鐨勫疄鐜般?br />```
- s := grpc.NewServer()
+ s := grpc.NewServer(grpc.StatsHandler(&statshandler{}))
```
statshandler 闇瀹炵幇4涓柟娉曪紝鍙敤鍒?涓繛鎺ョ浉鍏崇殑鏂規硶錛孴agConn() 鍜?HandleConn(),
鍙﹀2涓?TagRPC() 鍜?HandleRPC() 鐢ㄤ簬RPC緇熻, 瀹炵幇涓虹┖銆?br />
```go
type statshandler struct{}
// TagConn 鐢ㄦ潵緇欒繛鎺ユ墦涓爣絳撅紝浠ユ鏉ユ爣璇嗚繛鎺?瀹炲湪鏄壘涓嶅嚭榪樻湁浠涔堝姙娉曟潵鏍囪瘑榪炴帴).
// 榪欎釜鏍囩鏄釜鎸囬拡錛屽彲淇濊瘉姣忎釜榪炴帴鍞竴銆?/span>
// 灝嗚鎸囬拡娣誨姞鍒頒笂涓嬫枃涓幓錛岄敭涓?connCtxKey{}.
func (h *statshandler) TagConn(ctx context.Context, info *stats.ConnTagInfo) context.Context {
return context.WithValue(ctx, connCtxKey{}, info)
}
// TagRPC 涓虹┖.
func (h *statshandler) TagRPC(ctx context.Context, info *stats.RPCTagInfo) context.Context {
return ctx
}
// HandleConn 浼氬湪榪炴帴寮濮嬪拰緇撴潫鏃惰璋冪敤錛屽垎鍒細杈撳叆涓嶅悓鐨勭姸鎬?
func (h *statshandler) HandleConn(ctx context.Context, s stats.ConnStats) {
tag, ok := getConnTagFromContext(ctx)
if !ok {
log.Fatal("can not get conn tag")
}
connsMutex.Lock()
defer connsMutex.Unlock()
switch s.(type) {
case *stats.ConnBegin:
conns[tag] = ""
log.Printf("begin conn, tag = (%p)%#v, now connections = %d\n", tag, tag, len(conns))
case *stats.ConnEnd:
delete(conns, tag)
log.Printf("end conn, tag = (%p)%#v, now connections = %d\n", tag, tag, len(conns))
default:
log.Printf("illegal ConnStats type\n")
}
}
// HandleRPC 涓虹┖.
func (h *statshandler) HandleRPC(ctx context.Context, s stats.RPCStats) {
}
```
鐢ㄤ竴涓猰ap鏉ョ鐞嗘墍鏈夎繛鎺ワ紝浠ヨ繛鎺ョ殑鏍囩(鏄釜鎸囬拡)涓洪敭錛屽間負涓婃璇鋒眰鑰呯殑鍚嶅瓧銆?br />鍥犱負鏈夊綰跨▼璁塊棶錛屾墍鏈夊姞涓?Mutex 鏉ヤ繚鎶ゃ?br />榪炴帴緇撴潫鏃訛紝灝嗕粠 conns 涓垹闄よ繛鎺ョ浉鍏崇殑鏁版嵁銆?br />
```go
var connsMutex sync.Mutex
var conns map[*stats.ConnTagInfo]string = make(map[*stats.ConnTagInfo]string)
```
getConnTagFromContext() 浠庝笂涓嬫枃涓彇榪炴帴鏍囩錛?br />
```go
type connCtxKey struct{}
func getConnTagFromContext(ctx context.Context) (*stats.ConnTagInfo, bool) {
tag, ok := ctx.Value(connCtxKey{}).(*stats.ConnTagInfo)
return tag, ok
}
```
鏈鍚庡皢 SayHello() 鏀逛負璁板綍璇鋒眰鑰呭悕瀛楋紝騫惰繑鍥炰笂嬈¤姹傝呯殑鍚嶅瓧銆?br />
```go
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
tag, _ := getConnTagFromContext(ctx)
log.Printf("SayHello(), conn tag = (%p)%#v\n", tag, tag)
connsMutex.Lock()
defer connsMutex.Unlock()
prev := conns[tag]
conns[tag] = in.Name
return &pb.HelloReply{Message: fmt.Sprintf("Hello '%s' (prev '%s')", in.Name, prev)}, nil
}
```
嫻嬭瘯澶氫釜瀹㈡埛绔繛鎺ワ紝鍙互鐪嬪埌姣忎釜瀹㈡埛绔湁鑷繁鐨勭姸鎬侊紝浜掍笉褰卞搷銆?br />
```
E:\Git\grpc-go\examples\helloworld (master)
λ go run greeter_server/main.go
2017/12/25 18:39:03 start
2017/12/25 18:39:11 begin conn, tag = (0xc042182040)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0420818f0), LocalAddr:(*net.TCPAddr)(0xc0420818c0)}, now connections = 1
2017/12/25 18:39:11 SayHello(), conn tag = (0xc042182040)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0420818f0), LocalAddr:(*net.TCPAddr)(0xc0420818c0)}
2017/12/25 18:39:13 SayHello(), conn tag = (0xc042182040)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0420818f0), LocalAddr:(*net.TCPAddr)(0xc0420818c0)}
2017/12/25 18:39:13 begin conn, tag = (0xc0421ae200)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0421de060), LocalAddr:(*net.TCPAddr)(0xc0421de030)}, now connections = 2
2017/12/25 18:39:13 SayHello(), conn tag = (0xc0421ae200)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0421de060), LocalAddr:(*net.TCPAddr)(0xc0421de030)}
2017/12/25 18:39:15 SayHello(), conn tag = (0xc042182040)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0420818f0), LocalAddr:(*net.TCPAddr)(0xc0420818c0)}
2017/12/25 18:39:15 SayHello(), conn tag = (0xc0421ae200)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0421de060), LocalAddr:(*net.TCPAddr)(0xc0421de030)}
2017/12/25 18:39:17 SayHello(), conn tag = (0xc042182040)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0420818f0), LocalAddr:(*net.TCPAddr)(0xc0420818c0)}
2017/12/25 18:39:17 SayHello(), conn tag = (0xc0421ae200)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0421de060), LocalAddr:(*net.TCPAddr)(0xc0421de030)}
2017/12/25 18:39:19 end conn, tag = (0xc042182040)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0420818f0), LocalAddr:(*net.TCPAddr)(0xc0420818c0)}, now connections = 1
2017/12/25 18:39:19 SayHello(), conn tag = (0xc0421ae200)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0421de060), LocalAddr:(*net.TCPAddr)(0xc0421de030)}
2017/12/25 18:39:21 end conn, tag = (0xc0421ae200)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0421de060), LocalAddr:(*net.TCPAddr)(0xc0421de030)}, now connections = 0
```
]]>
(閲戝簡鐨勪笓鏍?2017.11)
Lile 鏄竴涓伐鍏鳳紝鐢ㄤ簬 Go 璇█蹇熷垱寤?gRPC 鏈嶅姟銆?br />https://github.com/lileio/lile
浼氳嚜鍔ㄦ坊鍔?Prometheus, Zipkin 鍜?Google PubSub 鏀寔銆?br />
go get -u github.com/lileio/lile/...
灝嗗畨瑁呮墍鏈変緷璧栧寘錛屽茍鐢熸垚 bin/lile.exe, bin/protoc-gen-lile-server.exe.
鍙﹀榪橀渶瑕佸畨瑁?protoc.exe.
鎸夌収紺轟緥鍒涘緩 users 鏈嶅姟錛?br />
E:\gopath\src\github.com
λ lile new jinq0123/users
Creating project in E:\gopath\src\github.com\jinq0123\users
Is this OK? [y]es/[n]o
y
.
├── server
│ ├── server.go
│ └── server_test.go
├── subscribers
│ └── subscribers.go
├── users
│ ├── cmd
│ │ ├── root.go
│ │ ├── serve.go
│ │ ├── subscribe.go
│ │ └── up.go
│ └── main.go
├── users.proto
├── Makefile
├── Dockerfile
├── .travis.yml
└── .gitignore
鏌ョ湅 Makefile, 澶嶅埗鍏朵腑 protoc 鑴氭湰錛屽皢 $$GOPATH 鏀逛負 %GOPATH%錛岃繍琛岋細
E:\gopath\src\github.com\jinq0123\users
λ protoc -I . users.proto --lile-server_out=. --go_out=plugins=grpc:%GOPATH%/src
2017/11/28 16:59:24 [Creating] server\read.go
2017/11/28 16:59:24 [Creating test] server\read_test.go
protoc-gen-lile-server.exe 灝嗙敓鎴?server\read.go, 瀵瑰簲 user.proto 涓殑鏂規硶 Users::Read().
grpc鐨勬彃浠跺皢鐢熸垚 users.pb.go錛屼笌浠呬粎鐢?grpc 鐢熸垚鐨勪唬鐮佺浉鍚屻?br />
D:/Go/bin/go.exe install -v [E:/gopath/src/github.com/jinq0123/users/users]
github.com/jinq0123/users/users
鎴愬姛: 榪涚▼閫鍑轟唬鐮?0.
鍙洿鎺ョ紪璇戠敓鎴?user.exe.
鏃犲弬鏁拌繍琛屽垯鏄劇ず鍛戒護琛屽府鍔╋細
E:\gopath\src\github.com\jinq0123\users
λ users
A gRPC based service
Usage:
users [command]
Available Commands:
help Help about any command
serve Run the RPC server
subscribe Subscribe to and process queue messages
up up runs both RPC and pubub subscribers
Flags:
-h, --help help for users
Use "users [command] --help" for more information about a command.
鐢ㄥ瓙鍛戒護serve鍚姩鏈嶅姟錛?br />
E:\gopath\src\github.com\jinq0123\users
λ users serve
INFO[0000] Serving gRPC on :8000
INFO[0000] Using Zipkin Global tracer
INFO[0000] Prometheus metrics at :9000/metrics
http://localhost:9000/metrics 浼氭樉紺?br />
# HELP go_gc_duration_seconds A summary of the GC invocation durations.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 0
go_gc_duration_seconds{quantile="0.25"} 0
...
鐢?grpc-lua 鏉ユ祴璇曚笅錛?br />
E:\Git\grpc-lua\examples\helloworld (master)
λ lua-cpp.exe
Lua 5.3.4 Copyright (C) 1994-2017 Lua.org, PUC-Rio
> package.path = "../../src/lua/?.lua;" .. package.path
> grpc = require("grpc_lua.grpc_lua")
> grpc.import_proto_file("users.proto")
> stub = grpc.service_stub("localhost:8000", "users.Users")
D1128 17:28:13.711000000 4612 dns_resolver.c:301] Using native dns resolver
> request = {id = "abcd"}
> response, err, cod = stub:sync_request("Read", request)
> cod
2
> insp = require("inspect")
> insp(resonse)
nil
> insp(err)
"not yet implemented"
緙虹渷瀹炵幇榪斿洖 "not yet implemented" 閿欒銆傛洿鏀瑰疄鐜頒唬濡備笅錛?br />
func (s UsersServer) Read(ctx context.Context, r *users.Request) (*users.Response, error) {
// return nil, errors.New("not yet implemented")
return &users.Response{Id: "Hello, " + r.Id}, nil
}
鍐嶆璇鋒眰錛?br />
> response, err, cod = stub:sync_request("Read", request)
> err
Endpoint read failed
...
> response, err, cod = stub:sync_request("Read", request)
> err
nil
> insp(response)
{
id = "Hello, abcd"
}
]]>
(閲戝簡鐨勪笓鏍?2017.11)
Googol 鍏竷鐨?API Design 瑙勮寖涓紝*.proto 涓殑鏋氫婦緙虹渷鍊煎緩璁負 ENUN_TYPE_UNSPECIFIED銆?br />
https://mp.weixin.qq.com/s?__biz=MzA5ODg4Mzk2OQ==&mid=2247483705&idx=1&sn=cc2ffef9ac431510c1791dbe6e774b85
The first value should be named ENUM_TYPE_UNSPECIFIED as it is returned when an enum value is not explicitly specified.
enum FooBar {
// The first value represents the default and must be == 0.
FOO_BAR_UNSPECIFIED = 0;
FIRST_VALUE = 1;
SECOND_VALUE = 2;
}
鍙傝冿細protobuf涓殑鏋氫婦緙虹渷鍊煎簲璇ヤ負UNKNOWN
http://blog.csdn.net/jq0123/article/details/52219597
]]>鐢?dep 浠f浛 go get 鏉ヨ幏鍙栫鏈夊簱
(閲戝簡鐨勪笓鏍?2017.11)
go get
鍔熻兘姣旇緝寮憋紝鏃犳硶鑾峰彇鍒嗘敮錛屾爣絳撅紝鐗瑰畾鐗堟湰錛宖ork, 鑰?dep
鍙互鍋氬埌銆?code>dep 榪樺彲浠ヨ幏鍙栫鏈夊簱銆?/p>
鐢?gitee.com 縐佹湁搴撲綔嫻嬭瘯銆傚垱寤?gogettest 搴撱?/p>
鍙敤錛?/p>
go get -u gitee.com/jinq0123/gogettest
濡傛灉鏀逛負縐佹湁搴撳垯澶辮觸錛?/p>
λ go get -v gitee.com/jinq0123/gogettest
Fetching https://gitee.com/jinq0123/gogettest?go-get=1
Parsing meta tags from https://gitee.com/jinq0123/gogettest?go-get=1 (status code 403)
package gitee.com/jinq0123/gogettest: unrecognized import path "gitee.com/jinq0123/gogettest" (parse https://gitee.com/jinq0123/gogettest?go-get=1: no go-import meta tags ())
go get -u github.com/golang/dep/cmd/dep
1
鍦ㄩ」鐩洰褰曚笅榪愯錛?/p>
dep init
鐢熸垚 Gopkg.toml
鍜?Gopkg.lock
鍦?Gopkg.toml 涓坊鍔狅細
娉ㄦ剰搴撳悕鏀規垚浜?jinq012345
, 榪欐牱瀵煎叆錛?
imort "gitee.com/jinq012345/gogettest"
name鍜宻ource鐨勮緗彲鏀寔浠?fork 搴撹幏鍙栥?/p>
gogettest
搴?/h3> dep ensure
浼氬脊鍑?https 鐨勭櫥褰曠敤鎴峰悕鍜屽瘑鐮佽緭鍏ユ銆?/p>