Silverlight+WCF 实战-网络象棋最终篇之对战视频-下篇[客户端发送与服务端中转](六)...
本篇继上一篇:Silverlight+WCF 实战-网络象棋最终篇之对战视频-上篇[客户端开启视频/注册编号/接收视频](五)
一:对战视频 简单原理
二:对战视频 步骤解析:
三:对战视频 具体实施
1:如何打开视频
2:Silverlight如何使用Socket进行通讯
2.1:与远程建立链接:
2.2:注册编号[这里的规则是“房间号+棋手颜色值”]
2.3:开新线程,等待接收对方视频
2.4:将视频显示出来,需要用主线程来操作
3:图片压缩与视频发送
3.1:图片压缩
因此,找一种图片压缩算法,是一种开始:
一开始:是从网上down了个PngEncoder,压缩160*160的截图后,图片大小是40K,看成是4K[因为看字节时是4后面好多0,看少了一个0],兴奋的我~~~
因此一开始在本地测试是正常的,上到网上就oh..no了。
40K*5,即每秒要发送200K的数据,这样就等于把2M/200K带宽给用光了,房东那限制的512K/56K带宽,就更提不上了~~~
最后:还是用上了大伙普通通用的JpgEncoder,压缩160*160的截图后,图片大小是10K,每秒产生10K*5=50K,56K带宽刚好够用了。
由于JpgEncoder为第三方插件,因此其代码就不贴了,下面简单介绍下:
2:JpgEncoder.cs有一静态方法,直接可以获取Stream流:
public static Stream GetStream(WriteableBitmap bitmap)
3:没了~~~
ps:具体FJ.Core.dll、JpgEncoder.cs两个文件可以从下载源码下找到。
3.2 视频发送
为了定时发送视频,我们需要开启定时器:
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)
{
//这里就是发送视频的代码了
}
private void btnSend_Click(object sender, RoutedEventArgs e)
{
timer.Start();//点击发送视频时,启动定时器即可
}
在点击发送触发定时器时,发送视频
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);//这里只管发送,发送后的结果不管了。
img = null;
}
至此,客户端的一系列动作就完成了,包括[打开视频/注册编号/发送视频/接收视频],下面到服务端代码上场了。
4:控制台服务端Socket中转
4.1:额外的处理事件
虽然这里没用WCF,改用Socket方式,一样需要解决跨域问题。
第二:用Socket通讯方式,还需要开启另外的943端口监听。
不过这两步,网上都有现成的代码,直接copy就可以了。
步骤如下:
1:新建控制台项目—》起名:TCPService
2:新建类文件:PolicyServer.cs,完整代码如下,大伙直接使用就可以了:
3:控制台启动首行代码
{
PolicyServer ps = new PolicyServer(SocketPolicy.Policy);//Silverlight跨域访问与开启943端口
}
至此,我们添加了个额外的处理类来解决943端口和跨域问题[注意上面代码中xml的端口号配置范围哦],下面开始自己的服务端处理流程
4.2:服务端处理流程
4.2.1:开启监听
{
class Program
{
public static Dictionary<int, ThreadProxy> soketList;//房号+颜色值
static void Main(string[] args)
{
PolicyServer ps = new PolicyServer(SocketPolicy.Policy);//Silverlight跨域访问及943端口
//主线程监听
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("有人来了----");
//下面开启处理逻辑
}
}
}
说明:
4.2.2 定义下全局变量
ThreadProxy youThreadProxy;//对方
bool firstConn = true;//是否第一次建立链接,首次链接都是注册编号,不发送视频的;
4.2.3 处理编号注册、移除、查找对方
编号注册:
{
firstConn = false;//注册完后,设置下标识
if (key.Length < 10)//字节太多就是图片流了
{
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;
}
}
}
线程错误,编号移除:
{
if (errorProxy.socket != null)
{
errorProxy.socket.Close();
}
Console.WriteLine("删除用户:" + errorProxy.num +"错误信息:"+ errorMsg);
Program.soketList.Remove(errorProxy.num);
}
查询对方:
{
int youNum = num % 2 == 0 ? num - 1 : num + 1;
if (Program.soketList.ContainsKey(youNum))
{
youThreadProxy = Program.soketList[youNum];
}
}
4.2.4 主业务处理中转流程
{
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);//关键点,请求太快数据接收不全
length = socket.Receive(buffer, count, socket.Available, 0);
count = count + length;
}
while (socket.Available > 0);
if (count > 1)
{
if (count < 4)//小字节,命令字符
{
if (firstConn)//首次登陆,需要注册ID
{
string key = ASCIIEncoding.ASCII.GetString(buffer, 0, count);
RegSocket(key);
}
}
else if (youThreadProxy == null)
{
Program.WriteLine("没人接收。。。");
FindYouSocket();
}
else if (youThreadProxy.canReceive)//对方允许接收图片发送
{
Program.WriteLine("图片来了:" + count);
if (youThreadProxy.socket.Connected)
{
Program.WriteLine("图片转发:" + buffer.Length);
try
{
youThreadProxy.socket.Send(buffer, count, 0);
}
catch(Exception err)
{
OnError(youThreadProxy, err.Message);
}
}
}
}
}
else
{
OnError(this,"socket链接已关闭");
break;
}
}
}
catch(Exception err)
{
OnError(this,err.Message);
}
}
处理流程也很简单,根据请求的字节大小来调用是“注册”还是“中转”。
至此,整个完整的视频传输篇完成了,完成的图片和上一节一样了:
最后是大家期待已久的示例源码下载:点击下载 [别忘了留下言推荐下哦^-^]
说明:视频源码中的内容会多一些,包括一开始我写的一些其它杂七杂八的代码,不过不影响整个的运行。
最后:谢谢大家对本系列的喜欢,谢谢支持~
PS:传说点一下推荐会有10个园豆,喜欢麻烦点一下“推荐”,thank you very much!!
版权声明:本文原创发表于博客园,作者为路过秋天,原文链接:
http://www.cnblogs.com/cyq1162/archive/2010/12/03/1895177.html
Silverlight+WCF 实战-网络象棋最终篇之对战视频-下篇[客户端发送与服务端中转](六)...相关推荐
- Silverlight+WCF 实战-网络象棋最终篇之对战视频-上篇[客户端开启视频/注册编号/接收视频](五)...
前言: 近期在忙点"秋色园"的事情,所以网络象棋这一块文章就写的相对慢,而且刚好接上篇:Silverlight+WCF 实战-网络象棋最终篇之非线程阻塞倒计时窗口(四) 之后, ...
- Silverlight+WCF 实战-网络象棋最终篇之非线程阻塞倒计时窗口(四)
前言: 在前面的系列中,我们虽然完成了其大部分功能,但是,离正真运行,还是有一大段距离 当你F5运行时,在弹出对话框之后,如果你不即时点确定,或者上个WC回来之后,你会发现已经提示出错了 这节开始,我 ...
- Silverlight+WCF 实战-网络象棋最终篇之解决重复的消息提示(八)
前言: 最近有网友经常会问,在跟着做象棋对战的通讯中,在重复退出进入的时候,消息会重复出现,本节就这问题进行解说与优化. 一:分析问题产生的原因? 1:首先看App.xaml,里面定义了一个全局客户端 ...
- Silverlight+WCF 新手实例 象棋 主界面-事件区-求和认输(三十二)
在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 事隔几篇,我们又回到事件区,继续其它两个按钮事件,来张图吧: 在Silverlight+WCF 新手实例 象棋 主界面-事件区- ...
- Silverlight+WCF 新手实例 象棋 主界面-棋谱-回放-结局(四十)
在线演示地址: Silverlight+WCF 新手实例 象棋 在线演示 在Silverlight+WCF 新手实例 象棋 主界面-棋谱-回放(三十九)中,我们实现了用户的棋谱回放,在文章的下面,我们 ...
- Silverlight+WCF 新手实例 象棋 主界面-棋谱-获取列表(三十八)
2019独角兽企业重金招聘Python工程师标准>>> 在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 在Silverlight+WCF 新手实例 象棋 主界 ...
- Silverlight+WCF 新手实例 象棋 主界面-实时聊天区(二十五)
在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 演示已更新到此节介绍:Silverlight+WCF 新手实例 象棋 介绍III(二十三) 本节连着Silverlight+WC ...
- Silverlight+WCF 新手实例 象棋 该谁下棋-B下A停(三十)
2019独角兽企业重金招聘Python工程师标准>>> 在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 上上一节,就是二十八节:Silverlight+WCF ...
- Silverlight+WCF 新手实例 象棋 主界面-事件区-返回退出(三十三)
在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 还是那张图: 本节实现返回大厅和退出系统: 一:返回大厅,其实很简单的说,就是转向房间列表了. 可是,转向前也有很多事情要处理的 ...
最新文章
- 【附可运行代码】剑指 Offer 12. 矩阵中的路径
- mysql 协议的query包及解析
- postman 无法正常返回结果 Could not get any response
- cache工作的详细过程
- 域控服务器取消验证_Linux 开发笔记《使用CentOS 7进行初始服务器设置》
- 「CSS」常见的清除浮动方法
- Vue3+CLI4 使用Element-ui
- 知道python_看完这篇文章,你就知道Python是什么?
- Java 全栈工程师进阶路线图
- 高性能计算机介绍,曙光个人高性能计算机介绍
- SSL Virtual Private Network的技术分析
- parse_calls大于executions
- 【二叉树的遍历-3】后序遍历(递归与非递归)
- 417. 太平洋大西洋水流问题
- Learn OpenGL 笔记7.4 PBR-Specular IBL(Image based lighting-特殊的基于图像的照明)
- CSS中clientHeight、offsetHeight、scrollHeight、scrollTop、scrollTo几者的区别和关联
- 【毕业设计_课程设计】在线免费小说微信小程序的设计与实现(源码+论文)
- 老贴纪念六(纪念热得快君)
- OVS代码结构(by quqi99)
- FP-growth:从FP树中挖掘频繁项集