日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

Silverlight+WCF 实战-网络象棋最终篇之对战视频-下篇[客户端发送与服务端中转](六)...

發(fā)布時間:2025/6/15 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Silverlight+WCF 实战-网络象棋最终篇之对战视频-下篇[客户端发送与服务端中转](六)... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本篇繼上一篇:Silverlight+WCF 實戰(zhàn)-網(wǎng)絡(luò)象棋最終篇之對戰(zhàn)視頻-上篇[客戶端開啟視頻/注冊編號/接收視頻](五)

?

?一:對戰(zhàn)視頻?簡單原理

略,內(nèi)容見上篇。

?

二:對戰(zhàn)視頻?步驟解析:

略,內(nèi)容見上篇。

?

三:對戰(zhàn)視頻?具體實施

1:如何打開視頻

略,內(nèi)容見上篇。

?

2:Silverlight如何使用Socket進行通訊

2.1:與遠程建立鏈接:

2.2:注冊編號[這里的規(guī)則是“房間號+棋手顏色值”]

2.3:開新線程,等待接收對方視頻

2.4:將視頻顯示出來,需要用主線程來操作

略,以上內(nèi)容見上篇。作者:路過秋天?博客:http://cyq1162.cnblogs.com/?秋色園:http://www.cyqdata.com/

?

3:圖片壓縮與視頻發(fā)送

3.1:圖片壓縮

我們發(fā)送的視頻,是通過定時器每秒截5張圖發(fā)送過去的,每秒鐘將產(chǎn)生5張圖片,因此,圖片壓縮變的相當重要。

因此,找一種圖片壓縮算法,是一種開始:

一開始:是從網(wǎng)上down了個PngEncoder,壓縮160*160的截圖后,圖片大小是40K,看成是4K[因為看字節(jié)時是4后面好多0,看少了一個0],興奮的我~~~

因此一開始在本地測試是正常的,上到網(wǎng)上就oh..no了。

40K*5,即每秒要發(fā)送200K的數(shù)據(jù),這樣就等于把2M/200K帶寬給用光了,房東那限制的512K/56K帶寬,就更提不上了~~~

最后:還是用上了大伙普通通用的JpgEncoder,壓縮160*160的截圖后,圖片大小是10K,每秒產(chǎn)生10K*5=50K,56K帶寬剛好夠用了。

?

由于JpgEncoder為第三方插件,因此其代碼就不貼了,下面簡單介紹下:

1:JpgEncoder下載后內(nèi)容為:FJ.Core.dll、JpgEncoder.cs兩個文件。

2:JpgEncoder.cs有一靜態(tài)方法,直接可以獲取Stream流:

?public?static?Stream?GetStream(WriteableBitmap?bitmap)

3:沒了~~~

ps:具體FJ.Core.dll、JpgEncoder.cs兩個文件可以從下載源碼下找到。

?

3.2 視頻發(fā)送

為了定時發(fā)送視頻,我們需要開啟定時器:

????????System.Windows.Threading.DispatcherTimer?timer;//全局定義
?????????public?MainPage()
????????{
????????????InitializeComponent();
????????????timer?
=?new?System.Windows.Threading.DispatcherTimer();
????????????timer.Interval?
=?TimeSpan.FromSeconds(0.2);//0.2秒一次,每秒5次
????????????timer.Tick?+=?new?EventHandler(timer_Tick);??????????
????????}
????????
void?timer_Tick(object?sender,?EventArgs?e)
????????{
???????????
//這里就是發(fā)送視頻的代碼了
????????}
????????
private?void?btnSend_Click(object?sender,?RoutedEventArgs?e)
????????{
????????????timer.Start();
//點擊發(fā)送視頻時,啟動定時器即可
????????}

在點擊發(fā)送觸發(fā)定時器時,發(fā)送視頻

????????byte[]?content?=?new?byte[56?*?1024];
????????
int?length;???????
????????
void?timer_Tick(object?sender,?EventArgs?e)
????????{
????????????WriteableBitmap?img?
=?new?WriteableBitmap(canVideo,?null);
????????????Stream?stream?
=?JpgEncoder.GetStream(img);?//獲取壓縮后的流
????????????length?=?(int)stream.Length;
????????????stream.Read(content,?
0,?length);
????????????stream.Close();

????????????SocketAsyncEventArgs?sendEvent?
=?new?SocketAsyncEventArgs();
????????????sendEvent.SetBuffer(content,?
0,?length);
????????????videoSocket.SendAsync(sendEvent);
//這里只管發(fā)送,發(fā)送后的結(jié)果不管了。
???????????
????????????img?
=?null;
????????}

?

至此,客戶端的一系列動作就完成了,包括[打開視頻/注冊編號/發(fā)送視頻/接收視頻],下面到服務(wù)端代碼上場了。

?

4:控制臺服務(wù)端Socket中轉(zhuǎn)

4.1:額外的處理事件

第一:服務(wù)端需要解決跨域問題,這個看過:Silverlight+WCF 新手實例 象棋 WCF通訊跨域(十五)--就會明白Silverlight客戶端和通訊端不在同一站點下通訊時,需要解決跨域問題了。

雖然這里沒用WCF,改用Socket方式,一樣需要解決跨域問題。

第二:用Socket通訊方式,還需要開啟另外的943端口監(jiān)聽。

?

不過這兩步,網(wǎng)上都有現(xiàn)成的代碼,直接copy就可以了。

步驟如下:

1:新建控制臺項目—》起名:TCPService

2:新建類文件:PolicyServer.cs,完整代碼如下,大伙直接使用就可以了:

PolicyServer類與跨域xml文件

3:控制臺啟動首行代碼

?static?void?Main(string[]?args)
?{
????PolicyServer?ps?
=?new?PolicyServer(SocketPolicy.Policy);//Silverlight跨域訪問與開啟943端口
??}

?

至此,我們添加了個額外的處理類來解決943端口和跨域問題[注意上面代碼中xml的端口號配置范圍哦],下面開始自己的服務(wù)端處理流程

?

4.2:服務(wù)端處理流程

4.2.1:開啟監(jiān)聽

namespace?TCPService
{
????
class?Program
????{
????????
public?static?Dictionary<int,?ThreadProxy>?soketList;//房號+顏色值
?????????static?void?Main(string[]?args)
????????{
????????????PolicyServer?ps?
=?new?PolicyServer(SocketPolicy.Policy);//Silverlight跨域訪問及943端口
????????????
//主線程監(jiān)聽
????????????soketList?=?new?Dictionary<int,?ThreadProxy>();
????????????Console.WriteLine(
"TCPService正在啟動運行");
????????????IPEndPoint?ip?
=?new?IPEndPoint(IPAddress.Any,?4505);//本地任意IP及4505端口
????????????Socket?mainSocket?=?new?Socket(AddressFamily.InterNetwork,?SocketType.Stream,?ProtocolType.Tcp);
????????????mainSocket.Bind(ip);
????????????mainSocket.Listen(
-1);
????????????
while?(true)
????????????{
????????????????Socket?socket?
=?mainSocket.Accept();
????????????????
new?ThreadProxy(socket).Run();//收到消息即時處理。

????????????}
????????}
????????
public?static?void?WriteLine(string?msg)
????????{
????????????Console.WriteLine(msg);
????????}
????}
????
class?ThreadProxy
????{
????????
public?Socket?socket;
????????
public?ThreadProxy(Socket?newSocket)
????????{
????????????socket?
=?newSocket;
????????}
????????
public?void?Run()
????????{
????????????Thread?thread?
=?new?Thread(new?ThreadStart(Action));
????????????thread.Start();
????????}
????????
public?void?Action()
????????{
????????????Program.WriteLine(
"有人來了----");
????????????
//下面開啟處理邏輯
????????}
???}
}

?

說明:

這里要注意的是監(jiān)聽的端口號必須要跨域文件配置的范圍內(nèi)。同時用一字典泛型soketList保存了所以注冊的用戶通訊socket,這樣可以方便查找對方的socket進行中轉(zhuǎn)。

?

4.2.2 定義下全局變量

????????public?Socket?socket;//我方的Socket
????????ThreadProxy?youThreadProxy;//對方 ????????int?num;//注冊的編號 ????????byte[]?buffer?=?new?byte[30?*?1024];//緩沖字節(jié)30K,簡單說就是用戶10K發(fā)送3次,這里收到滿30K才轉(zhuǎn)發(fā)一次
????????bool?firstConn?=?true;//是否第一次建立鏈接,首次鏈接都是注冊編號,不發(fā)送視頻的;

?

4.2.3 處理編號注冊、移除、查找對方

編號注冊:

????????private?void?RegSocket(string?key)
????????{
????????????firstConn?
=?false;//注冊完后,設(shè)置下標識
????????????if?(key.Length?<?10)//字節(jié)太多就是圖片流了
????????????{
????????????????
if?(int.TryParse(key,?out?num))
????????????????{
????????????????????
if?(Program.soketList.ContainsKey(num))//之前都有人在了
???????????????????????{
????????????????????????Program.soketList[num].socket.Close();
????????????????????????Program.soketList[num].socket.Dispose();
????????????????????????Program.soketList.Remove(num);
????????????????????}
????????????????????Program.soketList.Add(num,?
this);
????????????????????Program.WriteLine(
"用戶注冊:"?+?key);
????????????????????FindYouSocket();
????????????????????
return;
????????????????}
????????????}
????????}

線程錯誤,編號移除:

???????private?void?OnError(ThreadProxy?errorProxy,string?errorMsg)
????????{
????????????
if?(errorProxy.socket?!=?null)
????????????{
????????????????errorProxy.socket.Close();
????????????}
????????????Console.WriteLine(
"刪除用戶:"?+?errorProxy.num?+"錯誤信息:"+?errorMsg);
????????????Program.soketList.Remove(errorProxy.num);
????????????
????????}

查詢對方:

???????private?void?FindYouSocket()
???????{
????????????
int?youNum?=?num?%?2?==?0???num?-?1?:?num?+?1;
????????????
if?(Program.soketList.ContainsKey(youNum))
????????????{
????????????????youThreadProxy?
=?Program.soketList[youNum];
????????????}
?????????}

?

4.2.4 主業(yè)務(wù)處理中轉(zhuǎn)流程

???????public?ThreadProxy(Socket?newSocket)
????????{
????????????socket?
=?newSocket;
????????????socket.SendBufferSize?
=?buffer.Length;
????????????socket.ReceiveBufferSize?
=?buffer.Length;
????????}
????????
public?void?Run()
????????{
????????????Thread?thread?
=?new?Thread(new?ThreadStart(Action));
????????????thread.Start();
????????}
????????
public?void?Action()
????????{
????????????Program.WriteLine(
"有人來了----");
????????????
try
????????????{
????????????????
while?(true)
????????????????{
????????????????????
if?(socket.Connected)
????????????????????{
????????????????????????
int?length?=?0,?count?=?0;
????????????????????????
do
????????????????????????{
????????????????????????????System.Threading.Thread.Sleep(
20);//關(guān)鍵點,請求太快數(shù)據(jù)接收不全
????????????????????????????length?=?socket.Receive(buffer,?count,?socket.Available,?0);
????????????????????????????count?
=?count?+?length;

????????????????????????}
????????????????????????
while?(socket.Available?>?0);

????????????????????????
if?(count?>?1)
????????????????????????{

????????????????????????????
if?(count?<?4)//小字節(jié),命令字符
????????????????????????????{
????????????????????????????????
if?(firstConn)//首次登陸,需要注冊ID
????????????????????????????????{
????????????????????????????????????
string?key?=?ASCIIEncoding.ASCII.GetString(buffer,?0,?count);
????????????????????????????????????RegSocket(key);
????????????????????????????????}
????????????????????????????}
????????????????????????????
else?if?(youThreadProxy?==?null)
????????????????????????????{
????????????????????????????????Program.WriteLine(
"沒人接收。。。");
????????????????????????????????FindYouSocket();
????????????????????????????}
????????????????????????????
else?if?(youThreadProxy.canReceive)//對方允許接收圖片發(fā)送
????????????????????????????????{
????????????????????????????????Program.WriteLine(
"圖片來了:"?+?count);
????????????????????????????????
if?(youThreadProxy.socket.Connected)
????????????????????????????????{
????????????????????????????????????Program.WriteLine(
"圖片轉(zhuǎn)發(fā):"?+?buffer.Length);
????????????????????????????????????
try
????????????????????????????????????{
????????????????????????????????????????youThreadProxy.socket.Send(buffer,?count,?
0);
????????????????????????????????????}
????????????????????????????????????
catch(Exception?err)
????????????????????????????????????{
????????????????????????????????????????OnError(youThreadProxy,?err.Message);
????????????????????????????????????}
????????????????????????????????}
????????????????????????????}
????????????????????????}
????????????????????}
????????????????????
else
????????????????????{
????????????????????????OnError(
this,"socket鏈接已關(guān)閉");
????????????????????????
break;
????????????????????}
????????????????}
????????????}
????????????
catch(Exception?err)
????????????{
????????????????OnError(
this,err.Message);
????????????}

????????}

處理流程也很簡單,根據(jù)請求的字節(jié)大小來調(diào)用是“注冊”還是“中轉(zhuǎn)”。

至此,整個完整的視頻傳輸篇完成了,完成的圖片和上一節(jié)一樣了:

?

?

最后是大家期待已久的示例源碼下載:點擊下載?[別忘了留下言推薦下哦^-^]

說明:視頻源碼中的內(nèi)容會多一些,包括一開始我寫的一些其它雜七雜八的代碼,不過不影響整個的運行。

?

最后:謝謝大家對本系列的喜歡,謝謝支持~

PS:傳說點一下推薦會有10個園豆,喜歡麻煩點一下“推薦”,thank you very much!!

版權(quán)聲明:本文原創(chuàng)發(fā)表于博客園,作者為路過秋天,原文鏈接:

http://www.cnblogs.com/cyq1162/archive/2010/12/03/1895177.html

總結(jié)

以上是生活随笔為你收集整理的Silverlight+WCF 实战-网络象棋最终篇之对战视频-下篇[客户端发送与服务端中转](六)...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。