日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

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

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

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

?

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

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

?

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

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

?

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

1:如何打開視頻

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

?

2:Silverlight如何使用Socket進(jìn)行通訊

2.1:與遠(yuǎn)程建立鏈接:

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

2.3:開新線程,等待接收對(duì)方視頻

2.4:將視頻顯示出來(lái),需要用主線程來(lái)操作

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

?

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

3.1:圖片壓縮

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

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

一開始:是從網(wǎng)上down了個(gè)PngEncoder,壓縮160*160的截圖后,圖片大小是40K,看成是4K[因?yàn)榭醋止?jié)時(shí)是4后面好多0,看少了一個(gè)0],興奮的我~~~

因此一開始在本地測(cè)試是正常的,上到網(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為第三方插件,因此其代碼就不貼了,下面簡(jiǎn)單介紹下:

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

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

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

3:沒(méi)了~~~

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

?

3.2 視頻發(fā)送

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

????????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();
//點(diǎn)擊發(fā)送視頻時(shí),啟動(dòng)定時(shí)器即可
????????}

在點(diǎn)擊發(fā)送觸發(fā)定時(shí)器時(shí),發(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;
????????}

?

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

?

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

4.1:額外的處理事件

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

雖然這里沒(méi)用WCF,改用Socket方式,一樣需要解決跨域問(wèn)題。

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

?

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

步驟如下:

1:新建控制臺(tái)項(xiàng)目—》起名:TCPService

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

PolicyServer類與跨域xml文件

3:控制臺(tái)啟動(dòng)首行代碼

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

?

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

?

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

4.2.1:開啟監(jiān)聽

namespace?TCPService
{
????
class?Program
????{
????????
public?static?Dictionary<int,?ThreadProxy>?soketList;//房號(hào)+顏色值
?????????static?void?Main(string[]?args)
????????{
????????????PolicyServer?ps?
=?new?PolicyServer(SocketPolicy.Policy);//Silverlight跨域訪問(wèn)及943端口
????????????
//主線程監(jiān)聽
????????????soketList?=?new?Dictionary<int,?ThreadProxy>();
????????????Console.WriteLine(
"TCPService正在啟動(dòng)運(yùn)行");
????????????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();//收到消息即時(shí)處理。

????????????}
????????}
????????
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(
"有人來(lái)了----");
????????????
//下面開啟處理邏輯
????????}
???}
}

?

說(shuō)明:

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

?

4.2.2 定義下全局變量

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

?

4.2.3 處理編號(hào)注冊(cè)、移除、查找對(duì)方

編號(hào)注冊(cè):

????????private?void?RegSocket(string?key)
????????{
????????????firstConn?
=?false;//注冊(cè)完后,設(shè)置下標(biāo)識(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(
"用戶注冊(cè):"?+?key);
????????????????????FindYouSocket();
????????????????????
return;
????????????????}
????????????}
????????}

線程錯(cuò)誤,編號(hào)移除:

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

查詢對(duì)方:

???????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(
"有人來(lái)了----");
????????????
try
????????????{
????????????????
while?(true)
????????????????{
????????????????????
if?(socket.Connected)
????????????????????{
????????????????????????
int?length?=?0,?count?=?0;
????????????????????????
do
????????????????????????{
????????????????????????????System.Threading.Thread.Sleep(
20);//關(guān)鍵點(diǎn),請(qǐng)求太快數(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)//首次登陸,需要注冊(cè)ID
????????????????????????????????{
????????????????????????????????????
string?key?=?ASCIIEncoding.ASCII.GetString(buffer,?0,?count);
????????????????????????????????????RegSocket(key);
????????????????????????????????}
????????????????????????????}
????????????????????????????
else?if?(youThreadProxy?==?null)
????????????????????????????{
????????????????????????????????Program.WriteLine(
"沒(méi)人接收。。。");
????????????????????????????????FindYouSocket();
????????????????????????????}
????????????????????????????
else?if?(youThreadProxy.canReceive)//對(duì)方允許接收?qǐng)D片發(fā)送
????????????????????????????????{
????????????????????????????????Program.WriteLine(
"圖片來(lái)了:"?+?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);
????????????}

????????}

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

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

?

?

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

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

?

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

PS:傳說(shuō)點(diǎn)一下推薦會(huì)有10個(gè)園豆,喜歡麻煩點(diǎn)一下“推薦”,thank you very much!!

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

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

總結(jié)

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

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