Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.3/Drivers/EvaluationTCPChannel.cs @ 4068

Last change on this file since 4068 was 3895, checked in by abeham, 14 years ago

#866

  • Improved exception handling and added default client
File size: 6.2 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Net;
24using System.Net.Sockets;
25using Google.ProtocolBuffers;
26using HeuristicLab.Common;
27using HeuristicLab.Core;
28using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
29
30namespace HeuristicLab.Problems.ExternalEvaluation {
31  [Item("EvaluationTCPChannel", "A channel that creates a TCP connection over a network.")]
32  [StorableClass]
33  public class EvaluationTCPChannel : EvaluationChannel {
34    public const int MAX_VARINT32_SIZE = 5;
35
36    [Storable]
37    private string ipAddress;
38    public string IpAddress {
39      get { return ipAddress; }
40      set {
41        bool changed = !ipAddress.Equals(value);
42        ipAddress = value;
43        if (changed)
44          OnIpAddressChanged();
45      }
46    }
47    [Storable]
48    private int port;
49    public int Port {
50      get { return port; }
51      set {
52        bool changed = port != value;
53        port = value;
54        if (changed)
55          OnPortChanged();
56      }
57    }
58    private Socket socket;
59
60    public EvaluationTCPChannel() : this(String.Empty, 0) { }
61    public EvaluationTCPChannel(string ip, int port)
62      : base() {
63      this.ipAddress = ip;
64      this.port = port;
65    }
66
67    public override IDeepCloneable Clone(Cloner cloner) {
68      EvaluationTCPChannel clone = (EvaluationTCPChannel)base.Clone(cloner);
69      clone.ipAddress = ipAddress;
70      clone.port = port;
71      return clone;
72    }
73
74    #region IExternalEvaluationChannel Members
75
76    public override void Open() {
77      socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
78      socket.Connect(IPAddress.Parse(ipAddress), port);
79      if (socket.Connected) {
80        base.Open();
81        OnConnected();
82      }
83    }
84
85    public override void Send(IMessage message) {
86      try {
87        byte[] buffer = EncodeDelimited(message);
88        socket.Send(buffer);
89      } catch (SocketException) {
90        Close();
91        throw;
92      } catch (ObjectDisposedException) {
93        socket = null;
94        Close();
95        throw;
96      }
97    }
98
99    private byte[] EncodeDelimited(IMessage message) {
100      int messageSize = message.SerializedSize;
101      int headerSize = GetVarint32EncodedSize(messageSize);
102      byte[] buffer = new byte[headerSize + messageSize];
103      CodedOutputStream tmp = CodedOutputStream.CreateInstance(buffer);
104      tmp.WriteRawVarint32((uint)messageSize);
105      message.WriteTo(tmp);
106      return buffer;
107    }
108
109    private int GetVarint32EncodedSize(int size) {
110      // Varints in Protocol Buffers are encoded using the 7 lower order bits (the MSB indicates continuation (=1) or termination (=0))
111      int sizeByteCount = 1;
112      int limit = 128;
113      while (size >= limit) {
114        sizeByteCount++;
115        limit *= 128;
116      }
117      return sizeByteCount;
118    }
119
120    public override IMessage Receive(IBuilder builder) {
121      try {
122        byte[] buffer = GetMessageBuffer();
123        return builder.WeakMergeFrom(ByteString.CopyFrom(buffer)).WeakBuild();
124      } catch (SocketException) {
125        Close();
126        throw;
127      } catch (ObjectDisposedException) {
128        socket = null;
129        Close();
130        throw;
131      }
132    }
133
134    private byte[] GetMessageBuffer() {
135      byte[] buffer;
136      int messageSize = GetReceivedMessageSize(out buffer);
137      int headerSize = GetVarint32EncodedSize(messageSize);
138      int messageBytesInHeader = Math.Min(messageSize, buffer.Length - headerSize);
139      byte[] messageBuffer = new byte[messageSize];
140      Array.Copy(buffer, headerSize, messageBuffer, 0, messageBytesInHeader);
141      ReceiveMessage(messageBuffer, messageBytesInHeader, messageSize - messageBytesInHeader);
142      return messageBuffer;
143    }
144
145    private int GetReceivedMessageSize(out byte[] buffer) {
146      buffer = new byte[MAX_VARINT32_SIZE];
147      socket.Receive(buffer);
148      CodedInputStream tmp = CodedInputStream.CreateInstance(buffer);
149      return (int)tmp.ReadRawVarint32();
150    }
151
152    private void ReceiveMessage(byte[] buffer, int offset, int size) {
153      while (size > 0) {
154        int received = socket.Receive(buffer, offset, size, SocketFlags.None);
155        offset += received;
156        size -= received;
157      }
158    }
159
160    public override void Close() {
161      if (socket != null) {
162        try {
163          if (socket.Connected)
164            socket.Disconnect(false);
165          socket.Close();
166        } catch { }
167        socket = null;
168      }
169      bool wasInitialized = IsInitialized;
170      base.Close();
171      if (wasInitialized) OnDiconnected();
172    }
173
174    #endregion
175
176    #region Events
177    public event EventHandler IpAddressChanged;
178    protected void OnIpAddressChanged() {
179      EventHandler handler = IpAddressChanged;
180      if (handler != null) handler(this, EventArgs.Empty);
181    }
182    public event EventHandler PortChanged;
183    protected void OnPortChanged() {
184      EventHandler handler = PortChanged;
185      if (handler != null) handler(this, EventArgs.Empty);
186    }
187    public event EventHandler Connected;
188    protected void OnConnected() {
189      EventHandler handler = Connected;
190      if (handler != null) handler(this, EventArgs.Empty);
191    }
192    public event EventHandler Disconnected;
193    protected void OnDiconnected() {
194      EventHandler handler = Disconnected;
195      if (handler != null) handler(this, EventArgs.Empty);
196    }
197    #endregion
198  }
199}
Note: See TracBrowser for help on using the repository browser.