在C#中的异步插座任何时候发送消息给客户端列表 [英] Send a message back to a list of clients at any given time with async sockets in C#

查看:99
本文介绍了在C#中的异步插座任何时候发送消息给客户端列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Ive得到了一个异步服务器架设,它通过连接,接收和发送回一个消息到连接的客户端完美的作品。

Ive got an async server set up, it works perfectly by connecting, receiving and sending back a message to the connecting client.

服务器本身就是一个博弈世界服务器(MMORPG风格)。当用户将其位置以它的定位在哪里,我需要用一个PlayerPositionNotice这推到所有客户端。我知道我在这里缺少一些基本的东西,但是当我尝试保存在accept方法创建的StateObject,并使用该接口信息,因为在关闭套接字失败任意给定时间发回给玩家。 = /不知道为什么会这样,我也已经搜查了几个发动机的有关数据,但回来是空的。

The server itself is a Game-World-Server (mmorpg style). When a user sends its position to where its located, I need to push this out to all the clients with a PlayerPositionNotice. I know I'm missing some basic stuff here, but when i try to save the StateObject that was created in the accept method, and use that socket to send back information to the player at any given time it fails because the socket is closed. =/ Don't know why this happens and would I've searched a couple of engines on this but came back empty.

这是我如何创建我的服务器:

This is how i created my server:

首先,我们有全球的东西:

First off we have the global stuff:

    public StateManager _stateManager = new StateManager();
    public bool IsClosing = false;

    private const int _port = 1025;

    private IPHostEntry _localhost;
    private IPEndPoint _endpoint;
    private Socket _serverSocket;
    private Thread _serverThread;

我们的第二个具有初始化的东西:

Second of we have the initialize stuff:

    public void Start()
    {
        _serverThread = new Thread(Initialize);
        _serverThread.Start();
    }

    /// <summary>
    /// Main entry point for the server
    /// </summary>
    private void Initialize()
    {
        Console.WriteLine("Server Main Socket Thread Initialized.");

        _localhost = Dns.GetHostEntry(Dns.GetHostName());

        try
        {
            _endpoint = new IPEndPoint(_localhost.AddressList[0], _port);

            _serverSocket = new Socket(_endpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            _serverSocket.Bind(_endpoint);
            _serverSocket.Listen(100);

            _serverSocket.BeginAccept(new AsyncCallback(acceptCallback), _serverSocket);
        }
        catch (ArgumentOutOfRangeException)
        {
            Console.WriteLine(" >> Port number " + _port + " would seem to be invalid, should be between 1024 and 65000");
        }
        catch (SocketException)
        {
            Console.WriteLine(" >> Could not create socket, check to make sure not duplicating port");
        }
        catch (Exception e)
        {
            Console.WriteLine(" >> Error occured while binding socket, IE:" + e.InnerException);
        }
    }

到目前为止好,我期待。而现在到了服务器级的其余部分。

So far so good, i expect.. And now to the rest of the server class.

    private void acceptCallback(IAsyncResult result)
    {
        Console.WriteLine("Connection Accepted");
        StateObject state = null;

        try
        {
            state = new StateObject
            {
                workSocket = ((Socket)result.AsyncState).EndAccept(result)
            };

            _stateManager.AddConnection(state);


            state.workSocket.BeginReceive(state.buffer, 0, state.buffer.Length, 
                SocketFlags.None, new AsyncCallback(receiveCallback), state);

            _serverSocket.BeginAccept(new AsyncCallback(acceptCallback), _serverSocket);
        }
        catch (SocketException)
        {
            _stateManager.RemoveConnection(state);
            _serverSocket.BeginAccept(new AsyncCallback(acceptCallback), _serverSocket);
        }
        catch (Exception)
        {
            _stateManager.RemoveConnection(state);
            _serverSocket.BeginAccept(new AsyncCallback(acceptCallback), _serverSocket);
        }
    }

    private void receiveCallback(IAsyncResult result)
    {
        var state = (StateObject)result.AsyncState;

        try
        {
            // Buffer and count bytes read
            int bytesRead = state.workSocket.EndReceive(result);

            if (!state.workSocket.Connected)
                _stateManager.RemoveConnection(state);

            if (bytesRead > 0)
            {
                // Parse the message to the protocol manager and return a reply
                var replyingData = ProtocolManager.Parse(state.buffer);
                if (replyingData != null)
                    Send(replyingData, state);

                //Queue the next receive
                state.workSocket.BeginReceive(state.buffer, 0, state.buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), state);
            }
            else
            {
                _stateManager.RemoveConnection(state);
            }
        }
        catch (SocketException e)
        {
            _stateManager.RemoveConnection(state);
        }
    }

    public bool Send(byte[] message, StateObject state)
    {
        Console.WriteLine("Sending " + message.Length + " bytes");
        if (state != null && state.workSocket.Connected)
        {
            lock (state.workSocket)
            {
                //we use a blocking mode send, no async on the outgoing
                //since this is primarily a multithreaded application, shouldn't cause problems to send in blocking mode
                state.workSocket.Send(message, message.Length, SocketFlags.None);
            }
        }
        else return false;
        return true;
    }

StateManager的将包含StateObject的列表。下面你可以看到我是如何建造它们。

The stateManager contains a list of StateObject.. Below you can see how i build them.

状态管理器:

public class StateManager
{
    private List<StateObject> _connections = new List<StateObject>();

    public void AddConnection(StateObject so)
    {
        lock (_connections)
        {
            _connections.Add(so);
        }
    }

    public void RemoveConnection(StateObject so)
    {
        if (so.workSocket != null)
        {
            so.workSocket.Close();
            lock (_connections)
            {
                _connections.Remove(so);
            }
        }
    }
}

状态对象

public class StateObject
{
    public Socket workSocket = null;
    public const int BufferSize = 1024;
    public byte[] buffer = new byte[BufferSize];
    public StringBuilder sb = new StringBuilder();
}

在这里,我的问题是,每当有人在此列表中发送的东西,我想发回一个通知,很多​​其他客户。如何和我在哪里可以实现这一点?任何人都可以踢我在正确的方向? =)

My problem here is that whenever anybody in this list sends something i want to send back a notice to alot of other clients. How and where can i implement this? Anybody that can kick me in the right direction? =)

推荐答案

这code似乎是正确的,我不知道为什么你会得到关闭套接字的错误,但有一个问题:在发送(字节[]消息,StateObject状态)的方法,因为你从用户接收时,调用此和接收的数据发回给该用户。(不是所有其他用户看到他们)

This code seem to be correct and I don't know why you get "socket is closed" error, but there is another problem: in Send(byte[] message, StateObject state) method, because you call this when receiving from user and send received data back to that user.(not to all other users to notice them)

正如你所说,如果你需要发送新的位置,所有其他用户:

As you said, if you need to send new location to all other users:

在收到新的位置呼叫,而不是你的发送(字节[]消息,StateObject状态),此方法。

Call this method instead of your Send(byte[] message, StateObject state), when received new location.

public void NoticeAllusers(byte []buffer,StateObject state)
    {
        foreach(StateObject obj in _stateManager._connections)
        {
            if (obj != state)
            {
                obj.workSocket.BeginSend(buffer,<parameters you>...., new AsyncCallback(OnSend) state.workSocket);
            }
        }
    }

    public void OnSend(IAsyncResult ar)
    {
        try
        {
            Socket sock = (Socket)ar.AsyncState;
            sock.EndSend(ar);
        }
        catch { }
    }

我希望这将有助于一点点:)

I hope it will help a little :)

这篇关于在C#中的异步插座任何时候发送消息给客户端列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆