source: 2016/24/EemeliK/Nettipelijuttupelihymynaama/Nettipelijuttupelihymynaama/Nettipelijuttupelihymynaama/NetworkConnection.cs @ 7405

Revision 7405, 5.4 KB checked in by taeekotr, 3 years ago (diff)
Line 
1using System;
2using System.IO;
3using System.Linq;
4using System.Net;
5using System.Net.Sockets;
6using System.Reflection;
7using System.Runtime.Serialization;
8using System.Threading;
9using System.Runtime.Serialization.Formatters.Binary;
10using System.Text;
11
12
13public class NetworkConnection
14{
15    sealed class AssemblyBinder : SerializationBinder
16    {
17        public override Type BindToType(string assemblyName, string typeName)
18        {
19            return Type.GetType(String.Format("{0}, {1}", typeName, Assembly.GetExecutingAssembly().FullName));
20        }
21    }
22
23    private const int BLOCK_SIZE = 2048;
24
25    public readonly Guid guid;
26    private readonly byte[] guidBytes;
27    private readonly TcpClient client;
28    private readonly CancellationTokenSource cancelSource;
29    private readonly string gameName;
30    private NetworkStream networkStream;
31    private Thread receiveThread;
32
33    public delegate void MessageReceived(Guid id, string message);
34    public delegate void ConnectionChanged(Guid id);
35
36    public event MessageReceived OnMessageReceive;
37    public event ConnectionChanged OnConnect;
38    public event ConnectionChanged OnDisconnect;
39
40    public bool Connected { get; private set; }
41
42    public enum MessageType
43    {
44        Connected = 0, Disconnected, Message
45    }
46
47    public NetworkConnection(string gameName)
48    {
49        Connected = false;
50        this.gameName = gameName;
51        guid = Guid.NewGuid();
52        guidBytes = guid.ToByteArray();
53        cancelSource = new CancellationTokenSource();
54        client = new TcpClient();
55    }
56
57    public bool Connect(string ip, int port)
58    {
59        try
60        {
61            client.Connect(ip, port);
62        }
63        catch (SocketException)
64        {
65            return false;
66        }
67        networkStream = client.GetStream();
68        receiveThread = new Thread(() => ReceiveThread(cancelSource.Token));
69        receiveThread.Start();
70        Connected = true;
71        Send(MessageType.Connected);
72        return true;
73    }
74
75    public void Close()
76    {
77        if (!Connected) return;
78        Send(MessageType.Disconnected);
79        cancelSource.Cancel();
80        receiveThread.Join();
81        networkStream.Close();
82        client.Client.Close();
83        client.Close();
84        Connected = false;
85    }
86
87    private void Send(MessageType type, string message = "")
88    {
89        var builder = new StringBuilder();
90
91        builder.Append((int)type);
92        builder.Append('\x01');
93
94        builder.Append(Convert.ToBase64String(guidBytes));
95        builder.Append('\x01');
96
97        builder.Append(gameName);
98        builder.Append('\x01');
99
100        if (message.Length > 0)
101        {
102            builder.Append(message);
103            builder.Append('\x01');
104        }
105
106        builder.Append('\x00');
107
108        var bytes = Encoding.ASCII.GetBytes(builder.ToString());
109        networkStream.Write(bytes, 0, bytes.Length);
110        networkStream.Flush();
111    }
112
113    public void SendMessage(string message)
114    {
115        Send(MessageType.Message, message);
116    }
117
118    public T DeserializeFromString<T>(string settings) where T : class
119    {
120        var bytes = Convert.FromBase64String(settings);
121        using (var mstream = new MemoryStream(bytes))
122        {
123            var formatter = new BinaryFormatter();
124            formatter.Binder = new AssemblyBinder();
125            mstream.Seek(0, SeekOrigin.Begin);
126            return formatter.Deserialize(mstream) as T;
127        }
128    }
129
130    public void SendObject(object serializableObject)
131    {
132        using (var mstream = new MemoryStream())
133        {
134            var formatter = new BinaryFormatter();
135            formatter.Serialize(mstream, serializableObject);
136            mstream.Flush();
137            mstream.Position = 0;
138            SendMessage(Convert.ToBase64String(mstream.ToArray()));
139        }
140    }
141
142    private void ParsePacket(string packet)
143    {
144        var parts = packet.Split('\x01');
145
146        var messageType = (MessageType)int.Parse(parts[0]);
147        var senderGuid = new Guid(Convert.FromBase64String(parts[1]));
148        var game = parts[2];
149
150        if (messageType == MessageType.Message && OnMessageReceive != null)
151        {
152            var message = parts[3];
153            OnMessageReceive(senderGuid, message);
154        }
155        else if (messageType == MessageType.Connected && OnConnect != null)
156        {
157            OnConnect(senderGuid);
158        }
159        else if (messageType == MessageType.Disconnected && OnDisconnect != null)
160        {
161            OnDisconnect(senderGuid);
162        }
163    }
164
165    private void ReceiveThread(CancellationToken cancelToken)
166    {
167        var buffer = new StringBuilder();
168
169        while (!cancelToken.IsCancellationRequested)
170        {
171            if (client.Available == 0)
172                continue;
173
174            var receivedBytes = new byte[BLOCK_SIZE];
175            var bytesRead = networkStream.Read(receivedBytes, 0, BLOCK_SIZE);
176
177            for (int i = 0; i < bytesRead; i++)
178            {
179                if (receivedBytes[i] == '\x00')
180                {
181                    ParsePacket(buffer.ToString());
182                    buffer.Clear();
183                }
184                else
185                {
186                    buffer.Append((char)receivedBytes[i]);
187                }
188            }
189        }
190    }
191}
Note: See TracBrowser for help on using the repository browser.