【转】flex与c#基于socket的实时互动网络游戏编程教程二 .

这节讲讲如何用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代码:

<?xml version="1.0" encoding="gb2312"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"

                   layout="absolute"

                   initialize="connectToServer();">

     <mx:Script>

         <![CDATA[

 

        

         import flash.net.*;

         import flash.net.Socket;

         import flash.system.Security;

        

         import mx.controls.Alert;

             

         private var CurSocket:Socket=new Socket();

        

         private function connectToServer() : void

         {

 

             

             

         CurSocket.addEventListener(Event.CLOSE,close);

         CurSocket.addEventListener(ProgressEvent.SOCKET_DATA,receiveData);

         CurSocket.addEventListener(IOErrorEvent.IO_ERROR,ioErrorHandler);

         CurSocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR,securityHandler);

        

         CurSocket.connect("192.168.1.100",8888); //本机测试不要用127.0.0.1,否则连不上,不知原因

         }

        

         private function close(event: Event) : void

         {

         Alert.show("失去与服务器的连接!");

         }

        

         private function receiveData(event:ProgressEvent) : void

         {

 

              //trace("socketDataHandler: " + event);

              var message:String=CurSocket.readMultiByte(CurSocket.bytesAvailable,"GB2312");

              trace(message);

             

              if(message != "")

              {

                   MessageBoard.text += message + "/n";

              }

 

              /*

              try

              {

                   var buffer : ByteArray = new ByteArray();

                   CurSocket.readBytes(buffer,0,CurSocket.bytesAvailable);

                   var message : String = buffer.readUTF();

                   if(message != "")

                   {

                       MessageBoard.text += message + "/n";

                   }

                  

              }catch(ex : Error){}

              */

         }

        

         private function ioErrorHandler(event: IOErrorEvent) : void

         {

         Alert.show("IO_ERROR!");

         }

        

         private function securityHandler(event: SecurityErrorEvent) : void

         {

         Alert.show("SECURITY_ERROR!");

         Alert.show(event.toString());

         }

        

         private function send() : void

         {

         if(CurSocket.connected == true)

         {

         if(Message.text == "")

         {

         Alert.show("请输入要发送的信息!");

         return;

         }

         CurSocket.writeUTF(Message.text);

         CurSocket.flush();

         Message.text = "";

        

 

 

 

        

        

         }

         else

         {

         Alert.show("失去与服务器的连接!");

         }

         }

        

         ]]>

     </mx:Script>

    

     <mx:Button x="377.75" y="264" label="Send" click="send();"/>

     <mx:TextInput id="Message" x="18.25" y="264" width="351"/>

     <mx:TextArea id="MessageBoard" x="18.25" y="10" height="246" width="413.5"/>

    

</mx:Application>

 

 

C#代码

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using System.Net;

using System.Net.Sockets;

using System.Threading;

using System.IO;

 

namespace flexSocketWinFrom

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

 

        IPAddress localAddress;

        private const int port = 8888;

        private TcpListener myListener;

        private List<TcpClient> userList = new List<TcpClient>();

 

        public BinaryReader br;

        private BinaryWriter bw;

 

        private void Form1_Load(object sender, EventArgs e)

        {

            //IPAddress[] addrIP = Dns.GetHostAddresses(Dns.GetHostName());

            //localAddress = addrIP[0];

 

           localAddress = IPAddress.Parse("192.168.1.100");

        }

 

        private void button1_Click(object sender, EventArgs e)

        {

            myListener = new TcpListener(localAddress, port);

            myListener.Start();

            textBox1.Text = string.Format("开始在{0}:{1}监听客户连接", localAddress, port);

            //创建一个线程监听客户端连接请求

            Thread myThread = new Thread(ListenClientConnect);

            myThread.Start();

        }

 

        private void ListenClientConnect()

        {

 

            TcpClient newClient = null;

            while (true)

            {

                try

                {

                    newClient = myListener.AcceptTcpClient();//当有客户连接时执行一次下面的步骤

                }

                catch

                {

                    //当单击“停止监听”或者退出此窗体时AcceptTcpClient()会产生异常

                    //因此可以利用此异常退出循环

                    break;

                }

                //每接受一个客户端连接,就创建一个对应的线程循环接收该客户端发来的信息

                User user = new User(newClient);

                Thread threadReceive = new Thread(ReceiveData);

                threadReceive.Start(user);

 

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

 

                textShow(string.Format("[{0}]进入", newClient.Client.RemoteEndPoint));

                textShow(string.Format("当前连接用户数:{0}", userList.Count));

 

 

            }

 

        }

 

        //现成援引From控件

        delegate void SetTextCallback(string text);

        private void textShow(string str)

        {

            if (textBox1.InvokeRequired)

            {

                SetTextCallback d = textShow;

                textBox1.Invoke(d, str);

            }

 

            else

            {

                this.textBox1.Text = "/n" + textBox1.Text + str;

            }

 

 

        }

 

 

 

 

        private void ReceiveData(object userState)

        {

            User user = (User)userState;

            TcpClient client = user.client;

 

            while (true)

            {

                string receiveString = null;

                try

                {

 

                    textShow(string.Format("#接收前#"));

                    //这里会阻塞,直到接收到客户端消息。值得注意的是这里每一个user都是独立的(应该是因为在类中创建client的原因),之前连接的所有客用端都会被监听,而不会被覆盖

                    //如果直接在这创建client,则后面连接的client会覆盖掉前面连接的client,导致最后最后一个终端可以发消息

                    receiveString = user.br.ReadString();

                    textShow(string.Format("#接收后#"));

                }

                catch

                {

 

                    break;

                }

 

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

 

               

 

 

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

               // bw.Flush();

 

                //如果想给所有客用端发信息,在开始时应该把客用端保存在一个array里,然后这里用循环发送

                SendToAllClient(client, receiveString);

 

            }

        }

 

 

        /// <summary>发送信息给所有客户</summary>

        /// <param name="user">指定发给哪个用户</param>

        /// <param name="message">信息内容</param>

        private void SendToAllClient(TcpClient ClientUser, string message)

        {

            for (int i = 0; i < userList.Count; i++)

            {

 

                TcpClient client = (TcpClient)userList[i];

                NetworkStream networkStream = client.GetStream();

                //将网络流作为二进制读写对象

                br = new BinaryReader(networkStream);

                bw = new BinaryWriter(networkStream);

                bw.Write(System.Text.Encoding.GetEncoding("gb2312").GetBytes(message));

                bw.Flush();

            }

        }

 

 

    }

}

 

User.cs类

using System.Net.Sockets;

using System.IO;

 

namespace flexSocketWinFrom

{

    class User

    {

        public TcpClient client { get; private set; }

        public BinaryReader br { get; private set; }

        public BinaryWriter bw { get; private set; }

        public string userName { get; set; }

        public User(TcpClient client)

        {

            this.client = client;

            NetworkStream networkStream = client.GetStream();

            br = new BinaryReader(networkStream);

            bw = new BinaryWriter(networkStream);

        }

        public void Close()

        {

            br.Close();

            bw.Close();

            client.Close();

        }

    }

}

 

 

本例中的重点就是通过代码readMultiByte可以从flex或flash向服务器发送socket消息。你打开2个页面就可以测试了,本例未解决的两个问题是一、客用关掉flex页面,服务器是不知道的。Flex本身也没有吸构函数,在后面的教程中将会讲解如何用心跳测试法及时获得离开用户。二、本例在本机运行是没有问题的,但是放到iis或者tomcat下会有安全权限错误,就是沙箱限制,这个显示网上都是写通过设置策略文件xml解决,其实不然,socket的沙箱限制和http的是不一样。这2个问题在以后的教程中将会解答。

posted @ 2011-07-02 13:42  零纪录  阅读(423)  评论(0编辑  收藏  举报