本文目的
前段時間學習WCF已經漸入佳境,完成了既定學習目標,轉入分布式系統學習。本文技術路線是:
采用wcf實現分布式服務端和客戶端,客戶端部署於本地主機,nginx和WCF部署於虛擬機端(分別是三個虛擬機)
此文驗證:當其中一個服務端斷線后,另一個服務端可以繼續支撐整個會話的完成。
技術關鍵詞
wcf,nginx,虛擬機
(如果wcf基礎知識還不是很熟,建議先學習wcf技術知識。虛擬機采用vmware,虛擬機建立的系統是Win7.
提前准備好虛擬機,並建立三個虛擬機,每個虛擬機建立Win7系統,每個Win7系統安裝.NET4.6平台。
下載nginx程序包。)
准備工作:虛擬機與主機建立局域網
為了保障本文的測試成功,主機與三個虛擬機之間組成局域網。三個虛擬機完成下圖設置
三個虛擬機完成虛擬網路設置:
選擇VMnet8(因為此項外部連接是NAT模式),然后點擊NAT設置。
設置NAT網關設置
三個虛擬機還需要關閉防火牆和修改入站規則
我們來從自己本地主機ping虛擬機進行驗證。
我們從虛擬機向本地主機ping
以上就實現了每個虛擬機與主機的局域網建立。
wcf契約與Service
本文的wcf服務代碼沒有很特殊的地方,貼代碼

1 namespace NginxWCFTest_Contract 2 { 3 [ServiceContract] 4 public interface IOutputSomething 5 { 6 [OperationContract] 7 string GetContentData(int i); 8 [OperationContract] 9 string GetIpAddress(); 10 } 11 }

1 namespace NginxWCFTest_Service 2 { 3 public class OutputSomethingService:IOutputSomething 4 { 5 string threadName; 6 readonly object lockObject = new object(); 7 8 public string GetContentData(int i) 9 { 10 lock (lockObject) 11 { 12 threadName = i.ToString(0 + "-" + "我是主機:" + GetIpAddress()); 13 } 14 return string.Format("序列號:{0},線程號:{1}", i, threadName); 15 } 16 public string GetIpAddress() 17 { 18 string AddressIP = string.Empty; 19 foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList) 20 { 21 if (_IPAddress.AddressFamily.ToString() == "InterNetwork") 22 { 23 AddressIP = _IPAddress.ToString(); 24 } 25 } 26 return AddressIP; 27 } 28 } 29 }
wcf服務端宿主(部署於192.168.21.129和192.168.21.130)

1 namespace NginxWCFTest_Hosting 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 ServiceHost host = new ServiceHost(typeof(OutputSomethingService)); 8 host.Open(); 9 //host.Opened += delegate 10 //{ 11 // Console.WriteLine(host.Description.Endpoints[0].Address.Uri + "已經啟動,按任意鍵終止服務!"); 12 //}; 13 Console.Read(); 14 } 15 } 16 }
如果wcf基礎知識扎實的話, 宿主的代碼很easy,我們重點需要關注的是配置信息

<system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="metaBehavior"> <!-- 為避免泄漏元數據信息, 請在部署前將以下值設置為 false --> <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True" httpGetUrl="http://192.168.21.129:80/OutputSomethingService/meta"/> <!-- 要接收故障異常詳細信息以進行調試, 請將以下值設置為 true。在部署前設置為 false 以避免泄漏異常信息 --> <serviceDebug includeExceptionDetailInFaults="False" /> </behavior> </serviceBehaviors> </behaviors> <services> <service name="NginxWCFTest_Service.OutputSomethingService" behaviorConfiguration="metaBehavior"> <!--修改Binding為webHttpBinding--> <endpoint address="" binding="basicHttpBinding" contract="NginxWCFTest_Contract.IOutputSomething" > <identity> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> <host> <baseAddresses> <add baseAddress="http://192.168.21.129:80/OutputSomethingService/" /> </baseAddresses> </host> </service> </services> </system.serviceModel>
可以看得到服務端宿主的url端口是80,因為80是系統自帶的默認端口。一般80作為網頁服務器的訪問端口,比如一個網站的ip地址是123.123.123.123,我們訪問的是123.123.123.123:80 只是80是默認端口可以省略。
后面針對為什么用80端口會再一次介紹。
wcf客戶端宿主(部署於192.168.21.3)
客戶端宿主代碼跟普通沒有區別,唯一需要注意的是配置代碼

namespace NginxWCFTest_Client { class Program { static void Main(string[] args) { string AddressIP = string.Empty; foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList) { if (_IPAddress.AddressFamily.ToString() == "InterNetwork") { AddressIP = _IPAddress.ToString(); } } Console.WriteLine("本機IP是:" + AddressIP); using (ChannelFactory<IOutputSomething> channelFactory = new ChannelFactory<IOutputSomething>("OutputSomethingService")) { //ChannelFactory:一個創建不同類型通道的工廠,客戶端使用這些通道將消息發送到不同配置的服務終結點 //創建通道 IOutputSomething proxy = channelFactory.CreateChannel(); for (int i = 0; i < 20; i++) { Console.WriteLine(proxy.GetContentData(i)); } Console.Read(); } } }
大家可以看到客戶端指向的地址是jackchen.com地址。這個地址是nginx虛擬機的域名。為此,我們需要做以下事情。
主機域名處理
nginx虛擬機主機域名處理:
主機域名的文件路徑地址在“C:\Windows\System32\drivers\etc\hosts" 上圖紅箭頭為新增加域名,如果IE瀏覽器中輸入jackchen.com即相當於輸入http://192.168.21.128
WCF服務端主機域名處理
192.168.21.130與上圖類似,配置為192.168.21.130 jackchen.com。
wcf客戶端域名配置如下
nginx應用
上面講了WCF分布式服務的客戶端和服務端,也講了主機域名的處理。現在講講Nginx的作用和為什么要做域名處理
nginx的基礎知識我就多講了,此處鏈接http://tengine.taobao.org/book/chapter_09.html.
從上一步的主機域名解析就可以知道,WCF客戶端指向的是ngnix的虛擬機(192.168.21.128),然后由nginx做均衡負載和備份機制管理,
未使用nginx
使用nginx
nginx部署於192.168.21.128,需要對nginx文件夾中config文件進行配置。
配置信息為:

#user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; server { listen 80; server_name jackchen.com; #charset koi8-r; #access_log logs/host.access.log main; location / { autoindex off;#是否打開目錄瀏覽 root \html\Views\Home;#默認主頁目錄在nginx安裝目錄的html子目錄。 index Index.cshtml index.html index.htm;#起始頁 proxy_pass http://jackchen.com; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} } upstream linuxidc { server 127.0.0.1:8001; server 127.0.0.1:8002; server 127.0.0.1:8003; } upstream jackchen.com { server 192.168.21.129:80; server 192.168.21.130:80; } # another virtual host using mix of IP-, name-, and port-based configuration # #server { # listen 8000; # listen somename:8080; # server_name somename alias another.alias; # location / { # root html; # index index.html index.htm; # } #} # HTTPS server # #server { # listen 443 ssl; # server_name localhost; # ssl_certificate cert.pem; # ssl_certificate_key cert.key; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 5m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # location / { # root html; # index index.html index.htm; # } #} }
其中的修改點為:
upstream是配置集群,集群由192.168.21.129 和192.168.21.130組成
修改完了之后准備開啟nginx,下圖是進入nginx.exe所在的文件夾
接着輸入 start nginx可以啟動nginx,輸入nginx -s stop可以停止nginx,輸入nginx -s reload可以重啟nginx
效果展示
啟動兩個服務端和nginx,同時啟動客戶端,效果圖如下
關閉192.168.21.130效果圖如下