Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
strategic-game/Common/RemoteSide.cs
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
102 lines (91 sloc)
3.58 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Net; | |
using System.Net.Sockets; | |
namespace StrategicGame.Common { | |
public class RemoteSide<IncomingT, OutgoingT> : IDisposable | |
where IncomingT : Message | |
where OutgoingT : Message { | |
const int HEADER_SIZE = 2; | |
const int READ_BUFFER_SIZE = 4096; | |
TcpClient _client; | |
NetworkStream _stream; | |
byte[] _readBuffer = new byte[READ_BUFFER_SIZE]; | |
MemoryStream _writeMemStream; | |
BinaryReader _reader; | |
BinaryWriter _writer; | |
int _readPosition; | |
int _expectedLength = HEADER_SIZE; | |
Func<BinaryReader, IncomingT> _deserialize; | |
public RemoteSide(TcpClient client, Func<BinaryReader, IncomingT> deserialize) { | |
_client = client; | |
_stream = client.GetStream(); | |
_writeMemStream = new MemoryStream(); | |
_reader = new BinaryReader(new MemoryStream(_readBuffer)); | |
_writer = new BinaryWriter(_writeMemStream); | |
_deserialize = deserialize; | |
} | |
public EndPoint RemoteEndPoint { get { return _client.Client.RemoteEndPoint; } } | |
public bool Connected { get { return _client.Client.Connected; } } | |
public IncomingT ReadMessage() { | |
if (!_stream.DataAvailable) | |
return null; | |
IncomingT result = null; | |
int bytesRead = 0; | |
do { | |
if (DisconnectOnSocketError(() => { | |
bytesRead = _stream.Read( | |
_readBuffer, | |
_readPosition, | |
Math.Min(_expectedLength - _readPosition, READ_BUFFER_SIZE)); | |
})) | |
return null; | |
_readPosition += bytesRead; | |
if (_readPosition >= HEADER_SIZE) { | |
if (_expectedLength == HEADER_SIZE) { | |
_reader.BaseStream.Seek(0, SeekOrigin.Begin); | |
_expectedLength = _reader.ReadUInt16(); | |
} | |
if (_readPosition == _expectedLength) { | |
_reader.BaseStream.Seek(HEADER_SIZE, SeekOrigin.Begin); | |
result = _deserialize(_reader); | |
_expectedLength = HEADER_SIZE; | |
_readPosition = 0; | |
} | |
} | |
} while (bytesRead > 0 && result == null); | |
return result; | |
} | |
public void WriteMessage(OutgoingT msg) { | |
_writer.Seek(HEADER_SIZE, SeekOrigin.Begin); | |
msg.Serialize(_writer); | |
var length = (ushort)_writeMemStream.Position; | |
_writer.Seek(0, SeekOrigin.Begin); | |
_writer.Write(length); | |
DisconnectOnSocketError(() => | |
_stream.Write(_writeMemStream.GetBuffer(), 0, length)); | |
} | |
public void WriteMessages(IEnumerable<OutgoingT> msgs) { | |
foreach (var msg in msgs) | |
WriteMessage(msg); | |
} | |
public void Dispose() { | |
if (_stream != null) | |
_stream.Close(); | |
_client.Close(); | |
} | |
protected TcpClient Client { get { return _client; } } | |
bool DisconnectOnSocketError(Action a) { | |
try { | |
a(); | |
return false; | |
} catch (IOException ex) { | |
var socketException = ex.InnerException as SocketException; | |
if (socketException == null) | |
throw; | |
return true; | |
} | |
} | |
} | |
} |