Tun richtig & schnell-TCP-Netzwerke in c#

Ich versuche eine Lösung implementieren, wo Sie auf der service-Zeitpläne einige Arbeit, um eine Anzahl von Arbeitern. Die Planung selbst soll geschehen über ein einfaches tcp-basiertes Protokoll, weil der Arbeitnehmer kann entweder auf der gleichen oder auf einer anderen Maschine.

Nach einigen Recherchen fand ich diese post. Nach dem Lesen fand ich heraus, dass es mindestens 3 verschiedene mögliche Lösungen, jeder mit seinen vor-und disatvantages.

Habe ich beschlossen zu gehen für die Begin-End-Lösung, und schrieb ein kleines test-Programm zu spielen, um mit es.
Mein client ist nur ein einfaches Programm, dass sendet einige Daten an den server und wird dann beendet.
Dies ist der Client-Code:

class Client
{
    static void Main(string[] args)
    {
        var ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345);
        var s = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
        s.Connect(ep);
        Console.WriteLine("client Startet, socket connected");
        s.Send(Encoding.ASCII.GetBytes("1234"));
        s.Send(Encoding.ASCII.GetBytes("ABCDEFGH"));
        s.Send(Encoding.ASCII.GetBytes("A1B2C3D4E5F6"));
        Console.ReadKey();
        s.Close();
    }
}

Mein Server ist fast so einfach, nach dem Beispiel:

class Program
{
    static void Main(string[] args)
    {
        var server = new BeginEndTcpServer(8, 1, new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345));
        //var server = new ThreadedTcpServer(8, new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345));
        //server.ClientConnected += new EventHandler<ClientConnectedEventArgs>(server_ClientConnected);
        server.DataReceived += new EventHandler<DataReceivedEventArgs>(server_DataReceived);
        server.Start();
        Console.WriteLine("Server Started");
        Console.ReadKey();
    }

    static void server_DataReceived(object sender, DataReceivedEventArgs e)
    {
        Console.WriteLine("Receveived Data: " + Encoding.ASCII.GetString(e.Data));
    }
}


using System;
using System.Collections.Generic;
using System.Net; 
using System.Net.Sockets;

namespace TcpServerTest
{
public sealed class BeginEndTcpServer
{
    private class Connection
    {
        public Guid id;
        public byte[] buffer;
        public Socket socket;
    }

    private readonly Dictionary<Guid, Connection> _sockets;
    private Socket _serverSocket;
    private readonly int _bufferSize;
    private readonly int _backlog;
    private readonly IPEndPoint serverEndPoint;

    public BeginEndTcpServer(int bufferSize, int backlog, IPEndPoint endpoint)
    {
        _sockets = new Dictionary<Guid, Connection>();
        serverEndPoint = endpoint;
        _bufferSize = bufferSize;
        _backlog = backlog;
    }

    public bool Start()
    {
        //System.Net.IPHostEntry localhost = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName());
        try
        {
            _serverSocket = new Socket(serverEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
        }
        catch (System.Net.Sockets.SocketException e)
        {
            throw new ApplicationException("Could not create socket, check to make sure not duplicating port", e);
        }
        try
        {
            _serverSocket.Bind(serverEndPoint);
            _serverSocket.Listen(_backlog);
        }
        catch (Exception e)
        {
            throw new ApplicationException("Error occured while binding socket, check inner exception", e);
        }
        try
        {
            //warning, only call this once, this is a bug in .net 2.0 that breaks if 
            //you're running multiple asynch accepts, this bug may be fixed, but
            //it was a major pain in the ass previously, so make sure there is only one
            //BeginAccept running
            _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
        }
        catch (Exception e)
        {
            throw new ApplicationException("Error occured starting listeners, check inner exception", e);
        }
        return true;
    }

    public void Stop()
    {
        _serverSocket.Close();
        lock (_sockets)
            foreach (var s in _sockets)
                s.Value.socket.Close();
    }

    private void AcceptCallback(IAsyncResult result)
    {
        Connection conn = new Connection();
        try
        {
            //Finish accepting the connection
            System.Net.Sockets.Socket s = (System.Net.Sockets.Socket)result.AsyncState;
            conn = new Connection();
            conn.id = Guid.NewGuid();
            conn.socket = s.EndAccept(result);
            conn.buffer = new byte[_bufferSize];
            lock (_sockets)
                _sockets.Add(conn.id, conn);
            OnClientConnected(conn.id);
            //Queue recieving of data from the connection
            conn.socket.BeginReceive(conn.buffer, 0, conn.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), conn);
            //Queue the accept of the next incomming connection
            _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
        }
        catch (SocketException)
        {
            if (conn.socket != null)
            {
                conn.socket.Close();
                lock (_sockets)
                    _sockets.Remove(conn.id);
            }
            //Queue the next accept, think this should be here, stop attacks based on killing the waiting listeners
            _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
        }
        catch (Exception)
        {
            if (conn.socket != null)
            {
                conn.socket.Close();
                lock (_sockets)
                    _sockets.Remove(conn.id);
            }
            //Queue the next accept, think this should be here, stop attacks based on killing the waiting listeners
            _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
        }
    }

    private void ReceiveCallback(IAsyncResult result)
    {
        //get our connection from the callback
        Connection conn = (Connection)result.AsyncState;
        //catch any errors, we'd better not have any
        try
        {
            //Grab our buffer and count the number of bytes receives
            int bytesRead = conn.socket.EndReceive(result);
            //make sure we've read something, if we haven't it supposadly means that the client disconnected
            if (bytesRead > 0)
            {
                //put whatever you want to do when you receive data here
                conn.socket.Receive(conn.buffer);
                OnDataReceived(conn.id, (byte[])conn.buffer.Clone());
                //Queue the next receive
                conn.socket.BeginReceive(conn.buffer, 0, conn.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), conn);
            }
            else
            {
                //Callback run but no data, close the connection
                //supposadly means a disconnect
                //and we still have to close the socket, even though we throw the event later
                conn.socket.Close();
                lock (_sockets)
                    _sockets.Remove(conn.id);
            }
        }
        catch (SocketException)
        {
            //Something went terribly wrong
            //which shouldn't have happened
            if (conn.socket != null)
            {
                conn.socket.Close();
                lock (_sockets)
                    _sockets.Remove(conn.id);
            }
        }
    }

    public bool Send(byte[] message, Guid connectionId)
    {
        Connection conn = null;
        lock (_sockets)
            if (_sockets.ContainsKey(connectionId))
                conn = _sockets[connectionId];
        if (conn != null && conn.socket.Connected)
        {
            lock (conn.socket)
            {
                //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
                conn.socket.Send(message, message.Length, SocketFlags.None);
            }
        }
        else
            return false;
        return true;
    }

    public event EventHandler<ClientConnectedEventArgs> ClientConnected;
    private void OnClientConnected(Guid id)
    {
        if (ClientConnected != null)
            ClientConnected(this, new ClientConnectedEventArgs(id));
    }

    public event EventHandler<DataReceivedEventArgs> DataReceived;
    private void OnDataReceived(Guid id, byte[] data)
    {
        if (DataReceived != null)
            DataReceived(this, new DataReceivedEventArgs(id, data));
    }

    public event EventHandler<ConnectionErrorEventArgs> ConnectionError;

}

public class ClientConnectedEventArgs : EventArgs
{
    private readonly Guid _ConnectionId;
    public Guid ConnectionId { get { return _ConnectionId; } }

    public ClientConnectedEventArgs(Guid id)
    {
        _ConnectionId = id;
    }
}

public class DataReceivedEventArgs : EventArgs
{
    private readonly Guid _ConnectionId;
    public Guid ConnectionId { get { return _ConnectionId; } }

    private readonly byte[] _Data;
    public byte[] Data { get { return _Data; } }

    public DataReceivedEventArgs(Guid id, byte[] data)
    {
        _ConnectionId = id;
        _Data = data;
    }
}

public class ConnectionErrorEventArgs : EventArgs
{
    private readonly Guid _ConnectionId;
    public Guid ConnectionId { get { return _ConnectionId; } }

    private readonly Exception _Error;
    public Exception Error { get { return _Error; } }

    public ConnectionErrorEventArgs(Guid id, Exception ex)
    {
        _ConnectionId = id;
        _Error = ex;
    }
}

}

Mein problem ist: Der Server erhält nur einen Trank, der die Daten (in dem Beispiel erhält nur 'EFGHA1B2'). Auch wenn ich nur 4byte Daten, die der server nicht erhalten, bis die Verbindung geschlossen wird.
Das, was ich bin fehlt oder falsch??

Die andere Sache ist, im moment bin ich wirklich verwirrt von den verschiedenen Möglichkeiten, ist die Art und Weise mache ich das eine gute Lösung? Oder sollte ich etwas anderes versuchen?

Jede Hilfe wäre sehr geschätzt werden!

  • Warum stellen Sie die buffer size 8 bytes, statt der Einstellung es auf die Größe der Menge an text, die Sie brauchen, um zu senden.
  • Die Größe des Puffers ist, dass niedrig, weil es einige test-code, In meiner Produktion Anwendung habe ich möglicherweise befassen sich mit Datenmengen, die größer sind als meine verfügbaren Pufferspeicher. Eh, das überschreiben der Puffer sollte nicht passieren, in jedem Fall, also muss ich etwas falsch gemacht haben hier. Frage ist: was?
  • Es würde wahrscheinlich einfacher sein, um Ihren Worker-Anwendungen/ - Dienste hosten eines WCF-Diensts statt Programmieren mit sockets direkt. Sie können konfigurieren, dass ein WCF-Dienst für die Kommunikation über TCP, aber die eigentlichen socket-Kommunikation wird abstrahiert von Ihnen, so dass Sie nur wirklich Gedanken über die Definition der Operationen, die Arbeiter aussetzen und die Struktur der übergebenen Daten für jeden Betrieb.
InformationsquelleAutor Vertigo | 2011-11-10
Schreibe einen Kommentar