我已经设置了异步服务器,它通过连接,接收和发回消息到连接客户端完美地工作.
服务器本身是Game-World-Server(mmorpg风格).当用户将其位置发送到其所在的位置时,我需要使用PlayerPositionNotice将其推送到所有客户端.我知道我在这里缺少一些基本的东西,但是当我尝试保存在accept方法中创建的StateObject时,并使用该套接字在任何给定时间将信息发送回播放器,因为套接字已关闭而失败. = /不知道为什么会发生这种情况,我会在这个问题上搜索几个引擎但是又回来了.
这就是我创建服务器的方式:
首先,我们有全球性的东西:
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;
第二个我们有初始化的东西:
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);
}
}
到目前为止这么好,我希望..现在到服务器类的其余部分.
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列表.下面你可以看到我是如何构建它们的.
国家经理:
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();
}
我的问题在于,无论何时此列表中的任何人发送了我想要向其他客户发回通知的内容.我如何以及在何处实现此目的?谁能踢我正确的方向? =)
最佳答案 这段代码似乎是正确的,我不知道为什么你得到“socket is closed”错误,但是还有另一个问题:在Send(byte [] message,StateObject state)方法中,因为你在从用户接收时调用了这个将收到的数据发回给该用户(不是所有其他用户都注意到它们)
如您所说,如果您需要向所有其他用户发送新位置:
收到新位置时,调用此方法而不是Send(byte []消息,StateObject状态).
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 { }
}
我希望它会有所帮助:)