打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
【新提醒】flex与c#基于socket的实时互动网络游戏编程教程2

[教程]flex与c#基于socket的实时互动网络游戏编程教程2

查看: 4359|回复: 23

威望
1 点
义气
6 点
楼主
发表于 2011-4-13 21:03:28 |只看该作者
近些年webGame非常火爆,可惜相关教程实在少之又少,在我学习过程中无数次baidu,google。发现实际涉及wenGame核心的东西基本没有。于是就有了把我学习过程中使用和总结的代码拿上来给大家分享,让有共同爱好的同学们少走弯路。
本教程基于flex与c#,做到完全同步的游戏设计与编写。本教程只提供实现基本功能的代码,只要融会贯通,就能在此基础上制作出无比强大的网络游戏。
这篇教程最好是对c#有一定基础,会使用vs的同学。如果不会,我推荐看一下c#方面的书。
本教如需转载,请注名作者——汪舰,联系方式sxnrt#126.com。


这节讲讲如何用flex与c#进行socket通讯。
Flex端(当然你也完全可以用flash来写)使用import flash.net.Socket;包来做。通过ProgressEvent.SOCKET_DATA时刻检听是否接收到数据,接收到数据后触发函数receiveData。
使用var message:String=CurSocket.readMultiByte(CurSocket.bytesAvailable,"GB2312");可以把c#服务器发送过来的数据接收到。
CurSocket.writeUTF(Message.text);可以将数据发送给指定c#服务器
至于服务器端,只需要将第一节讲的代码稍加修改就可以使用。
需要注意的是这里要声明一个User类,其实本例中不使用类,直接在代码里声明TcpClient client也是可以的,做类的原因是在以后做游戏的时候,要给每一个连接进来的客户附加一些其他信息,比如用户名,血量,速度之类的,所以这里就先做成类的模式。
C#的代码很简单,等待连接,有客户连接后,把客户对象转换成自定义类User并保存到一个数组中。
当任何客户发送消息后,用循环向所有数组中的用户发送消息即可。下面请看代码。

Flex代码:
  1. <?xml version="1.0" encoding="gb2312"?>
  2. <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  3.                                 layout="absolute"
  4.                                 initialize="connectToServer();">
  5.         <mx:Script>
  6.                 <![CDATA[

  7.                
  8.                 import flash.net.*;
  9.                 import flash.net.Socket;
  10.                 import flash.system.Security;
  11.                
  12.                 import mx.controls.Alert;
  13.                        
  14.                 private var CurSocket:Socket=new Socket();
  15.                
  16.                 private function connectToServer() : void
  17.                 {

  18.                        
  19.                        
  20.                 CurSocket.addEventListener(Event.CLOSE,close);
  21.                 CurSocket.addEventListener(ProgressEvent.SOCKET_DATA,receiveData);
  22.                 CurSocket.addEventListener(IOErrorEvent.IO_ERROR,ioErrorHandler);
  23.                 CurSocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR,securityHandler);
  24.                
  25.                 CurSocket.connect("192.168.1.100",8888); //本机测试不要用127.0.0.1,否则连不上,不知原因
  26.                 }
  27.                
  28.                 private function close(event: Event) : void
  29.                 {
  30.                 Alert.show("失去与服务器的连接!");
  31.                 }
  32.                
  33.                 private function receiveData(event:ProgressEvent) : void
  34.                 {

  35.                         //trace("socketDataHandler: " + event);
  36.                         var message:String=CurSocket.readMultiByte(CurSocket.bytesAvailable,"GB2312");
  37.                         trace(message);
  38.                        
  39.                         if(message != "")
  40.                         {
  41.                                 MessageBoard.text += message + "\n";
  42.                         }

  43.                         /*
  44.                         try
  45.                         {
  46.                                 var buffer : ByteArray = new ByteArray();
  47.                                 CurSocket.readBytes(buffer,0,CurSocket.bytesAvailable);
  48.                                 var message : String = buffer.readUTF();
  49.                                 if(message != "")
  50.                                 {
  51.                                         MessageBoard.text += message + "\n";
  52.                                 }
  53.                                
  54.                         }catch(ex : Error){}
  55.                         */
  56.                 }
  57.                
  58.                 private function ioErrorHandler(event: IOErrorEvent) : void
  59.                 {
  60.                 Alert.show("IO_ERROR!");
  61.                 }
  62.                
  63.                 private function securityHandler(event: SecurityErrorEvent) : void
  64.                 {
  65.                 Alert.show("SECURITY_ERROR!");
  66.                 Alert.show(event.toString());
  67.                 }
  68.                
  69.                 private function send() : void
  70.                 {
  71.                 if(CurSocket.connected == true)
  72.                 {
  73.                 if(Message.text == "")
  74.                 {
  75.                 Alert.show("请输入要发送的信息!");
  76.                 return;
  77.                 }
  78.                 CurSocket.writeUTF(Message.text);
  79.                 CurSocket.flush();
  80.                 Message.text = "";
  81.                



  82.                
  83.                
  84.                 }
  85.                 else
  86.                 {
  87.                 Alert.show("失去与服务器的连接!");
  88.                 }
  89.                 }
  90.                
  91.                 ]]>
  92.         </mx:Script>
  93.        
  94.         <mx:Button x="377.75" y="264" label="Send" click="send();"/>
  95.         <mx:TextInput id="Message" x="18.25" y="264" width="351"/>
  96.         <mx:TextArea id="MessageBoard" x="18.25" y="10" height="246" width="413.5"/>
  97.        
  98. </mx:Application>
复制代码
C#代码
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. using System.Net;
  10. using System.Net.Sockets;
  11. using System.Threading;
  12. using System.IO;

  13. namespace flexSocketWinFrom
  14. {
  15.     public partial class Form1 : Form
  16.     {
  17.         public Form1()
  18.         {
  19.             InitializeComponent();
  20.         }

  21.         IPAddress localAddress;
  22.         private const int port = 8888;
  23.         private TcpListener myListener;
  24.         private List<TcpClient> userList = new List<TcpClient>();

  25.         public BinaryReader br;
  26.         private BinaryWriter bw;

  27.         private void Form1_Load(object sender, EventArgs e)
  28.         {
  29.             //IPAddress[] addrIP = Dns.GetHostAddresses(Dns.GetHostName());
  30.             //localAddress = addrIP[0];

  31.            localAddress = IPAddress.Parse("192.168.1.100");
  32.         }

  33.         private void button1_Click(object sender, EventArgs e)
  34.         {
  35.             myListener = new TcpListener(localAddress, port);
  36.             myListener.Start();
  37.             textBox1.Text = string.Format("开始在{0}:{1}监听客户连接", localAddress, port);
  38.             //创建一个线程监听客户端连接请求
  39.             Thread myThread = new Thread(ListenClientConnect);
  40.             myThread.Start();
  41.         }

  42.         private void ListenClientConnect()
  43.         {

  44.             TcpClient newClient = null;
  45.             while (true)
  46.             {
  47.                 try
  48.                 {
  49.                     newClient = myListener.AcceptTcpClient();//当有客户连接时执行一次下面的步骤
  50.                 }
  51.                 catch
  52.                 {
  53.                     //当单击“停止监听”或者退出此窗体时AcceptTcpClient()会产生异常
  54.                     //因此可以利用此异常退出循环
  55.                     break;
  56.                 }
  57.                 //每接受一个客户端连接,就创建一个对应的线程循环接收该客户端发来的信息
  58.                 User user = new User(newClient);
  59.                 Thread threadReceive = new Thread(ReceiveData);
  60.                 threadReceive.Start(user);

  61.                 userList.Add(newClient);//这个列表保存了所有连接中的用户

  62.                 textShow(string.Format("[{0}]进入", newClient.Client.RemoteEndPoint));
  63.                 textShow(string.Format("当前连接用户数:{0}", userList.Count));


  64.             }

  65.         }

  66.         //现成援引From控件
  67.         delegate void SetTextCallback(string text);
  68.         private void textShow(string str)
  69.         {
  70.             if (textBox1.InvokeRequired)
  71.             {
  72.                 SetTextCallback d = textShow;
  73.                 textBox1.Invoke(d, str);
  74.             }

  75.             else
  76.             {
  77.                 this.textBox1.Text = "\n" + textBox1.Text + str;
  78.             }


  79.         }




  80.         private void ReceiveData(object userState)
  81.         {
  82.             User user = (User)userState;
  83.             TcpClient client = user.client;

  84.             while (true)
  85.             {
  86.                 string receiveString = null;
  87.                 try
  88.                 {

  89.                     textShow(string.Format("#接收前#"));
  90.                     //这里会阻塞,直到接收到客户端消息。值得注意的是这里每一个user都是独立的(应该是因为在类中创建client的原因),之前连接的所有客用端都会被监听,而不会被覆盖
  91.                     //如果直接在这创建client,则后面连接的client会覆盖掉前面连接的client,导致最后最后一个终端可以发消息
  92.                     receiveString = user.br.ReadString();
  93.                     textShow(string.Format("#接收后#"));
  94.                 }
  95.                 catch
  96.                 {

  97.                     break;
  98.                 }

  99.                 textShow(string.Format("[{0}]被输出;", receiveString));

  100.                


  101.                // bw.Write(System.Text.Encoding.GetEncoding("gb2312").GetBytes(receiveString));
  102.                // bw.Flush();

  103.                 //如果想给所有客用端发信息,在开始时应该把客用端保存在一个array里,然后这里用循环发送
  104.                 SendToAllClient(client, receiveString);

  105.             }
  106.         }


  107.         /// <summary>发送信息给所有客户</summary>
  108.         /// <param name="user">指定发给哪个用户</param>
  109.         /// <param name="message">信息内容</param>
  110.         private void SendToAllClient(TcpClient ClientUser, string message)
  111.         {
  112.             for (int i = 0; i < userList.Count; i++)
  113.             {

  114.                 TcpClient client = (TcpClient)userList[i];
  115.                 NetworkStream networkStream = client.GetStream();
  116.                 //将网络流作为二进制读写对象
  117.                 br = new BinaryReader(networkStream);
  118.                 bw = new BinaryWriter(networkStream);
  119.                 bw.Write(System.Text.Encoding.GetEncoding("gb2312").GetBytes(message));
  120.                 bw.Flush();
  121.             }
  122.         }


  123.     }
  124. }
复制代码
  1. User.cs类
  2. using System.Net.Sockets;
  3. using System.IO;

  4. namespace flexSocketWinFrom
  5. {
  6.     class User
  7.     {
  8.         public TcpClient client { get; private set; }
  9.         public BinaryReader br { get; private set; }
  10.         public BinaryWriter bw { get; private set; }
  11.         public string userName { get; set; }
  12.         public User(TcpClient client)
  13.         {
  14.             this.client = client;
  15.             NetworkStream networkStream = client.GetStream();
  16.             br = new BinaryReader(networkStream);
  17.             bw = new BinaryWriter(networkStream);
  18.         }
  19.         public void Close()
  20.         {
  21.             br.Close();
  22.             bw.Close();
  23.             client.Close();
  24.         }
  25.     }
  26. }
复制代码
本例中的重点就是通过代码readMultiByte可以从flex或flash向服务器发送socket消息。你打开2个页面就可以测试了,本例未解决的两个问题是一、客用关掉flex页面,服务器是不知道的。Flex本身也没有吸构函数,在后面的教程中将会讲解如何用心跳测试法及时获得离开用户。二、本例在本机运行是没有问题的,但是放到iis或者tomcat下会有安全权限错误,就是沙箱限制,这个显示网上都是写通过设置策略文件xml解决,其实不然,socket的沙箱限制和http的是不一样。这2个问题在以后的教程中将会解答。
下一节开始讲如何使用flex+socket制作一个真正的互动游戏。

flex与c#聊天代码.zip(69.7 KB, 下载次数: 144)
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
VB.NET实现PC与掌上电脑PPC的双向通信
【新提醒】【简要C/S结构网络通讯层设计(一)】
☆《代码学习群教程》☆
C#网络编程(基本概念和操作) - Part.1 - C# 编程 - TraceFact....
C# Socket的TCP通讯
17.6 使用纹理滤波器分割图像(1) - 51CTO.COM
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服