├── .gitignore
├── .vs
└── JT808DataServer
│ └── v15
│ ├── .suo
│ └── sqlite3
│ └── storage.ide
├── DataGateway
├── Common
│ ├── ByteBuffer.cs
│ └── DateTimeEx.cs
├── GPS
│ ├── JT808
│ │ ├── Codec
│ │ │ └── JT808Decoder.cs
│ │ ├── Constant
│ │ │ ├── JT808Constant.cs
│ │ │ └── MessageResult.cs
│ │ ├── Data
│ │ │ ├── LocationInfo.cs
│ │ │ └── TerminalRegInfo.cs
│ │ ├── Handler
│ │ │ └── JT808ProInHandler.cs
│ │ ├── Messages
│ │ │ ├── JT808Message.cs
│ │ │ ├── JT808MessageBodyAttr.cs
│ │ │ ├── JT808MessageHead.cs
│ │ │ └── MessageSplitInfo.cs
│ │ ├── Model
│ │ │ ├── CommonPlatformResp.cs
│ │ │ ├── PlatformResp.cs
│ │ │ ├── ResponseData.cs
│ │ │ └── TerminalRegPlatformResp.cs
│ │ ├── Service
│ │ │ ├── BaseMsgProcessService.cs
│ │ │ ├── Session.cs
│ │ │ ├── SessionManager.cs
│ │ │ └── TerminalMsgProcessService.cs
│ │ └── Util
│ │ │ └── DataUtil.cs
│ └── Server
│ │ ├── DataServer.cs
│ │ └── DataServerInitializer.cs
├── JT808DataServer.csproj
├── Program.cs
└── obj
│ ├── DataGateway.csproj.nuget.cache
│ ├── DataGateway.csproj.nuget.g.props
│ ├── DataGateway.csproj.nuget.g.targets
│ ├── Debug
│ └── netcoreapp2.0
│ │ ├── DataGateway.AssemblyInfo.cs
│ │ ├── DataGateway.AssemblyInfoInputs.cache
│ │ ├── DataGateway.csproj.CopyComplete
│ │ ├── DataGateway.csproj.CoreCompileInputs.cache
│ │ ├── DataGateway.csproj.FileListAbsolute.txt
│ │ ├── DataGateway.csprojResolveAssemblyReference.cache
│ │ ├── DataGateway.dll
│ │ ├── DataGateway.pdb
│ │ ├── JT808DataServer.AssemblyInfo.cs
│ │ ├── JT808DataServer.AssemblyInfoInputs.cache
│ │ ├── JT808DataServer.csproj.CopyComplete
│ │ ├── JT808DataServer.csproj.CoreCompileInputs.cache
│ │ ├── JT808DataServer.csproj.FileListAbsolute.txt
│ │ ├── JT808DataServer.csprojResolveAssemblyReference.cache
│ │ ├── JT808DataServer.dll
│ │ └── JT808DataServer.pdb
│ ├── JT808DataServer.csproj.nuget.cache
│ ├── JT808DataServer.csproj.nuget.g.props
│ ├── JT808DataServer.csproj.nuget.g.targets
│ └── project.assets.json
├── JT808-2013.pdf
├── JT808DataServer.sln
├── README.md
└── Tool
├── NetAssist.exe
└── data.png
/.gitignore:
--------------------------------------------------------------------------------
1 | /obj/
2 | /bin/
3 | /DataGateway/bin
4 |
--------------------------------------------------------------------------------
/.vs/JT808DataServer/v15/.suo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mingyunet/JT808-Server/7d35386fdd650cfd5bf0ff9075c441bab6cfb224/.vs/JT808DataServer/v15/.suo
--------------------------------------------------------------------------------
/.vs/JT808DataServer/v15/sqlite3/storage.ide:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mingyunet/JT808-Server/7d35386fdd650cfd5bf0ff9075c441bab6cfb224/.vs/JT808DataServer/v15/sqlite3/storage.ide
--------------------------------------------------------------------------------
/DataGateway/Common/ByteBuffer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace JT808DataServer.Common
5 | {
6 | ///
7 | /// 数据包缓冲区类
8 | ///
9 | public class ByteBuffer : Stream
10 | {
11 | private MemoryStream _stream;
12 | private bool _autoExpand;
13 | private long _bookmark;
14 |
15 | ///
16 | /// Initializes a new instance of the ByteBuffer class.
17 | ///
18 | /// Wraps the MemoryStream into a buffer.
19 | public ByteBuffer(MemoryStream stream)
20 | {
21 | _stream = stream;
22 | ClearBookmark();
23 | }
24 |
25 | ///
26 | /// Allocates a new byte buffer.
27 | /// The new buffer's position will be zero, its limit will be its capacity,
28 | /// and its mark will be undefined.
29 | /// It will have a backing array, and its array offset will be zero.
30 | ///
31 | ///
32 | ///
33 | public static ByteBuffer Allocate(int capacity)
34 | {
35 | MemoryStream ms = new MemoryStream(capacity);
36 | ByteBuffer buffer = new ByteBuffer(ms);
37 | buffer.Limit = capacity;
38 | return buffer;
39 | }
40 |
41 | ///
42 | /// Wraps a byte array into a buffer.
43 | /// The new buffer will be backed by the given byte array; that is, modifications
44 | /// to the buffer will cause the array to be modified and vice versa.
45 | /// The new buffer's capacity will be array.length, its position will be offset,
46 | /// its limit will be offset + length, and its mark will be undefined.
47 | ///
48 | /// Byte array to wrap.
49 | /// Offset in the byte array.
50 | ///
51 | ///
52 | public static ByteBuffer Wrap(byte[] array, int offset, int length)
53 | {
54 | MemoryStream ms = new MemoryStream(array, offset, length, true, true);
55 | ms.Capacity = array.Length;
56 | ms.SetLength(offset + length);
57 | ms.Position = offset;
58 | return new ByteBuffer(ms);
59 | }
60 | ///
61 | /// Wraps a byte array into a buffer.
62 | /// The new buffer will be backed by the given byte array; that is, modifications
63 | /// to the buffer will cause the array to be modified and vice versa.
64 | /// The new buffer's capacity and limit will be array.length, its position will be zero,
65 | /// and its mark will be undefined.
66 | ///
67 | ///
68 | ///
69 | public static ByteBuffer Wrap(byte[] array)
70 | {
71 | return Wrap(array, 0, array.Length);
72 | }
73 |
74 | ///
75 | /// Turns on or off autoExpand
76 | ///
77 | public bool AutoExpand
78 | {
79 | get { return _autoExpand; }
80 | set { _autoExpand = value; }
81 | }
82 | ///
83 | /// Returns this buffer's capacity.
84 | ///
85 | public int Capacity
86 | {
87 | get { return (int)_stream.Capacity; }
88 | }
89 | ///
90 | /// Returns this buffer's limit.
91 | ///
92 | public int Limit
93 | {
94 | get { return (int)_stream.Length; }
95 | set { _stream.SetLength(value); }
96 | }
97 | ///
98 | /// Returns the number of elements between the current position and the limit.
99 | ///
100 | public int Remaining
101 | {
102 | get { return this.Limit - (int)this.Position; }
103 | }
104 | ///
105 | /// Tells whether there are any elements between the current position and the limit.
106 | ///
107 | public bool HasRemaining
108 | {
109 | get { return this.Remaining > 0; }
110 | }
111 | ///
112 | /// Gets the current bookmark value.
113 | ///
114 | public long Bookmark
115 | {
116 | get { return _bookmark; }
117 | }
118 | ///
119 | /// Sets this buffer's bookmark at its position.
120 | ///
121 | /// Returns this bookmark value.
122 | public long Mark()
123 | {
124 | _bookmark = this.Position;
125 | return _bookmark;
126 | }
127 | ///
128 | /// Clears the current bookmark.
129 | ///
130 | public void ClearBookmark()
131 | {
132 | _bookmark = -1;
133 | }
134 | ///
135 | /// Resets this buffer's position to the previously-marked position.
136 | /// Invoking this method neither changes nor discards the mark's value.
137 | ///
138 | public void Reset()
139 | {
140 | if (_bookmark != -1)
141 | this.Position = _bookmark;
142 | }
143 | ///
144 | /// Clears this buffer. The position is set to zero, the limit is set to the capacity, and the mark is discarded.
145 | ///
146 | public void Clear()
147 | {
148 | ClearBookmark();
149 | Position = 0;
150 | SetLength(0);
151 | }
152 |
153 | #if !(NET_1_1)
154 | ///
155 | /// Releases all resources used by this object.
156 | ///
157 | /// Indicates if this is a dispose call dispose.
158 | protected override void Dispose(bool disposing)
159 | {
160 | if (disposing)
161 | {
162 | if (_stream != null)
163 | _stream.Dispose();
164 | _stream = null;
165 | }
166 | base.Dispose(disposing);
167 | }
168 | #endif
169 |
170 | ///
171 | /// 返回该ByteBuffer的byte array
172 | ///
173 | ///
174 | public byte[] Array()
175 | {
176 | return _stream.ToArray();
177 | }
178 |
179 | ///
180 | /// Flips this buffer. The limit is set to the current position and then
181 | /// the position is set to zero. If the mark is defined then it is discarded.
182 | ///
183 | public void Flip()
184 | {
185 | ClearBookmark();
186 | this.Limit = (int)this.Position;
187 | this.Position = 0;
188 | }
189 | ///
190 | /// Rewinds this buffer. The position is set to zero and the mark is discarded.
191 | ///
192 | public void Rewind()
193 | {
194 | ClearBookmark();
195 | this.Position = 0;
196 | }
197 | ///
198 | /// Writes the given byte into this buffer at the current position, and then increments the position.
199 | ///
200 | ///
201 | ///
202 | public void Put(byte value)
203 | {
204 | this.WriteByte(value);
205 | }
206 | ///
207 | /// Relative bulk put method.
208 | ///
209 | /// This method transfers bytes into this buffer from the given source array.
210 | /// If there are more bytes to be copied from the array than remain in this buffer,
211 | /// that is, if length > remaining(), then no bytes are transferred and a
212 | /// BufferOverflowException is thrown.
213 | ///
214 | /// Otherwise, this method copies length bytes from the given array into this buffer,
215 | /// starting at the given offset in the array and at the current position of this buffer.
216 | /// The position of this buffer is then incremented by length.
217 | ///
218 | /// The array from which bytes are to be read.
219 | /// The offset within the array of the first byte to be read; must be non-negative and no larger than the array length.
220 | /// The number of bytes to be read from the given array; must be non-negative and no larger than length - offset.
221 | public void Put(byte[] src, int offset, int length)
222 | {
223 | _stream.Write(src, offset, length);
224 | }
225 | ///
226 | /// This method transfers the entire content of the given source byte array into this buffer.
227 | ///
228 | /// The array from which bytes are to be read.
229 | public void Put(byte[] src)
230 | {
231 | Put(src, 0, src.Length);
232 | }
233 | ///
234 | /// Appends a byte buffer to this ByteArray.
235 | ///
236 | /// The byte buffer to append.
237 | public void Append(byte[] src)
238 | {
239 | Append(src, 0, src.Length);
240 | }
241 | ///
242 | /// Appends a byte buffer to this ByteArray.
243 | ///
244 | /// The byte buffer to append.
245 | /// Offset in the byte buffer.
246 | /// Number of bytes to append.
247 | public void Append(byte[] src, int offset, int length)
248 | {
249 | long position = this.Position;
250 | this.Position = this.Limit;
251 | Put(src, offset, length);
252 | this.Position = position;
253 | }
254 |
255 | ///
256 | /// This method transfers the bytes remaining in the given source buffer into this buffer.
257 | /// If there are more bytes remaining in the source buffer than in this buffer,
258 | /// that is, if src.remaining() > remaining(), then no bytes are transferred
259 | /// and a BufferOverflowException is thrown.
260 | ///
261 | /// Otherwise, this method copies n = src.remaining() bytes from the given buffer into this buffer,
262 | /// starting at each buffer's current position. The positions of both buffers are then
263 | /// incremented by n.
264 | ///
265 | /// The source buffer from which bytes are to be read; must not be this buffer.
266 | public void Put(ByteBuffer src)
267 | {
268 | while (src.HasRemaining)
269 | Put(src.Get());
270 | }
271 | ///
272 | /// Transfers the specified number of bytes from the given source buffer into this buffer.
273 | ///
274 | /// The source buffer from which bytes are to be read; must not be this buffer.
275 | /// Number of bytes to transfer.
276 | public void Put(ByteBuffer src, int count)
277 | {
278 | for (int i = 0; i < count; i++)
279 | {
280 | Put(src.Get());
281 | }
282 | }
283 | ///
284 | /// Absolute put method.
285 | /// Writes the given byte into this buffer at the given index.
286 | ///
287 | /// The index.
288 | /// The byte to write.
289 | public void Put(int index, byte value)
290 | {
291 | _stream.GetBuffer()[index] = value;
292 | }
293 | ///
294 | /// Relative get method. Reads the byte at this buffer's current position, and then increments the position.
295 | ///
296 | ///
297 | public byte Get()
298 | {
299 | return (byte)this.ReadByte();
300 | }
301 | ///
302 | /// Reads a 4-byte signed integer using network byte order encoding.
303 | ///
304 | /// The 4-byte signed integer.
305 | public int GetInt()
306 | {
307 | // Read the next 4 bytes, shift and add
308 | byte[] bytes = this.ReadBytes(4);
309 | return ((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]);
310 | }
311 | ///
312 | /// Reads a 2-byte signed integer using network byte order encoding.
313 | ///
314 | /// The 2-byte signed integer.
315 | public short GetShort()
316 | {
317 | //Read the next 2 bytes, shift and add.
318 | byte[] bytes = this.ReadBytes(2);
319 | return (short)((bytes[0] << 8) | bytes[1]);
320 | }
321 | ///
322 | /// Absolute get method. Reads the byte at the given index.
323 | ///
324 | ///
325 | ///
326 | public byte Get(int index)
327 | {
328 | return _stream.GetBuffer()[index];
329 | }
330 |
331 | public byte this[int index]
332 | {
333 | get { return Get(index); }
334 | set { Put(index, value); }
335 | }
336 |
337 | ///
338 | /// Writes the stream contents to a byte array, regardless of the Position property.
339 | ///
340 | /// A new byte array.
341 | ///
342 | /// This method omits unused bytes in ByteBuffer from the array. To get the entire buffer, use the GetBuffer method.
343 | ///
344 | public byte[] ToArray()
345 | {
346 | return _stream.ToArray();
347 | }
348 |
349 | ///
350 | /// Returns the array of unsigned bytes from which this stream was created.
351 | ///
352 | ///
353 | /// The byte array from which this ByteBuffer was created, or the underlying array if a byte array was not provided to the ByteBuffer constructor during construction of the current instance.
354 | ///
355 | public byte[] GetBuffer()
356 | {
357 | return _stream.GetBuffer();
358 | }
359 | ///
360 | /// Compacts this buffer
361 | ///
362 | /// The bytes between the buffer's current position and its limit, if any,
363 | /// are copied to the beginning of the buffer. That is, the byte at
364 | /// index p = position() is copied to index zero, the byte at index p + 1 is copied
365 | /// to index one, and so forth until the byte at index limit() - 1 is copied
366 | /// to index n = limit() - 1 - p.
367 | /// The buffer's position is then set to n+1 and its limit is set to its capacity.
368 | /// The mark, if defined, is discarded.
369 | /// The buffer's position is set to the number of bytes copied, rather than to zero,
370 | /// so that an invocation of this method can be followed immediately by an invocation of
371 | /// another relative put method.
372 | ///
373 | public void Compact()
374 | {
375 | if (this.Position == 0)
376 | return;
377 | for (int i = (int)this.Position; i < this.Limit; i++)
378 | {
379 | byte value = this.Get(i);
380 | this.Put(i - (int)this.Position, value);
381 | }
382 | //this.Position = this.Limit - this.Position;
383 | //this.Limit = this.Capacity;
384 | this.Limit = this.Limit - (int)this.Position;
385 | this.Position = 0;
386 | }
387 |
388 | ///
389 | /// Forwards the position of this buffer as the specified size bytes.
390 | ///
391 | ///
392 | public void Skip(int size)
393 | {
394 | this.Position += size;
395 | }
396 | ///
397 | /// Fills this buffer with the specified value.
398 | ///
399 | ///
400 | ///
401 | public void Fill(byte value, int count)
402 | {
403 | for (int i = 0; i < count; i++)
404 | this.Put(value);
405 | }
406 |
407 | #region Stream
408 |
409 | ///
410 | /// Gets a value indicating whether the current stream supports reading.
411 | ///
412 | public override bool CanRead
413 | {
414 | get
415 | {
416 | return _stream.CanRead;
417 | }
418 | }
419 | ///
420 | /// Gets a value indicating whether the current stream supports seeking.
421 | ///
422 | public override bool CanSeek
423 | {
424 | get
425 | {
426 | return _stream.CanSeek;
427 | }
428 | }
429 | ///
430 | /// Gets a value indicating whether the current stream supports writing.
431 | ///
432 | public override bool CanWrite
433 | {
434 | get
435 | {
436 | return _stream.CanWrite;
437 | }
438 | }
439 | ///
440 | /// Closes the current stream and releases any resources associated with the current stream.
441 | ///
442 | public override void Close()
443 | {
444 | _stream.Close();
445 | }
446 | ///
447 | /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
448 | ///
449 | public override void Flush()
450 | {
451 | _stream.Flush();
452 | }
453 | ///
454 | /// Gets the length in bytes of the stream.
455 | ///
456 | public override long Length
457 | {
458 | get
459 | {
460 | return _stream.Length;
461 | }
462 | }
463 | ///
464 | /// Gets or sets the position within the current stream.
465 | ///
466 | public override long Position
467 | {
468 | get
469 | {
470 | return _stream.Position;
471 | }
472 | set
473 | {
474 | _stream.Position = value;
475 | if (_bookmark > value)
476 | {
477 | //discard bookmark
478 | _bookmark = 0;
479 | }
480 | }
481 | }
482 | ///
483 | /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
484 | ///
485 | /// An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source.
486 | /// The zero-based byte offset in buffer at which to begin storing the data read from the current stream.
487 | /// The maximum number of bytes to be read from the current stream.
488 | /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.
489 | public override int Read(byte[] buffer, int offset, int count)
490 | {
491 | return _stream.Read(buffer, offset, count);
492 | }
493 | ///
494 | /// Relative bulk get method.
495 | /// This method transfers bytes from this buffer into the given destination array.
496 | /// An invocation of this method behaves in exactly the same way as the invocation buffer.Get(a, 0, a.Length)
497 | ///
498 | /// An array of bytes.
499 | /// The total number of bytes read into the buffer.
500 | public int Read(byte[] buffer)
501 | {
502 | return _stream.Read(buffer, 0, buffer.Length);
503 | }
504 |
505 | ///
506 | /// Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream.
507 | ///
508 | /// The unsigned byte cast to an Int32, or -1 if at the end of the stream.
509 | public override int ReadByte()
510 | {
511 | return _stream.ReadByte();
512 | }
513 | ///
514 | /// Sets the position within the current stream.
515 | ///
516 | /// A byte offset relative to the origin parameter.
517 | /// A value of type SeekOrigin indicating the reference point used to obtain the new position.
518 | /// The new position within the current stream.
519 | public override long Seek(long offset, SeekOrigin origin)
520 | {
521 | return _stream.Seek(offset, origin);
522 | }
523 | ///
524 | /// Sets the length of the current stream.
525 | ///
526 | /// The desired length of the current stream in bytes.
527 | public override void SetLength(long value)
528 | {
529 | _stream.SetLength(value);
530 | }
531 | ///
532 | /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.
533 | ///
534 | /// An array of bytes. This method copies count bytes from buffer to the current stream.
535 | /// The zero-based byte offset in buffer at which to begin copying bytes to the current stream.
536 | /// The number of bytes to be written to the current stream.
537 | public override void Write(byte[] buffer, int offset, int count)
538 | {
539 | _stream.Write(buffer, offset, count);
540 | }
541 | ///
542 | /// Writes a byte to the current position in the stream and advances the position within the stream by one byte.
543 | ///
544 | /// The byte to write to the stream.
545 | public override void WriteByte(byte value)
546 | {
547 | _stream.WriteByte(value);
548 | }
549 |
550 | #endregion Stream
551 |
552 | ///
553 | /// Reads count bytes from the current stream into a byte array and advances the current position by count bytes.
554 | ///
555 | ///
556 | ///
557 | public byte[] ReadBytes(int count)
558 | {
559 | byte[] bytes = new byte[count];
560 | for (int i = 0; i < count; i++)
561 | {
562 | bytes[i] = (byte)this.ReadByte();
563 | }
564 | return bytes;
565 | }
566 | ///
567 | /// Writes a 32-bit signed integer to the current position using variable length unsigned 29-bit integer encoding.
568 | ///
569 | /// A 32-bit signed integer.
570 | public void WriteMediumInt(int value)
571 | {
572 | byte[] bytes = new byte[3];
573 | bytes[0] = (byte)(0xFF & (value >> 16));
574 | bytes[1] = (byte)(0xFF & (value >> 8));
575 | bytes[2] = (byte)(0xFF & (value >> 0));
576 | this.Write(bytes, 0, bytes.Length);
577 | }
578 |
579 | public void WriteReverseInt(int value)
580 | {
581 | byte[] bytes = new byte[4];
582 | bytes[3] = (byte)(0xFF & (value >> 24));
583 | bytes[2] = (byte)(0xFF & (value >> 16));
584 | bytes[1] = (byte)(0xFF & (value >> 8));
585 | bytes[0] = (byte)(0xFF & value);
586 | this.Write(bytes, 0, bytes.Length);
587 | }
588 |
589 | private void WriteBigEndian(byte[] bytes)
590 | {
591 | WriteBigEndian((int)this.Position, bytes);
592 | }
593 |
594 | private void WriteBigEndian(int index, byte[] bytes)
595 | {
596 | for (int i = bytes.Length - 1, j = 0; i >= 0; i--, j++)
597 | {
598 | this.Put(index + j, bytes[i]);
599 | }
600 | this.Position += bytes.Length;
601 | }
602 |
603 | private void WriteBytes(int index, byte[] bytes)
604 | {
605 | for (int i = 0; i < bytes.Length; i++)
606 | {
607 | this.Put(index + i, bytes[i]);
608 | }
609 | }
610 | ///
611 | /// Writes a 16-bit unsigned integer to the current position.
612 | ///
613 | /// A 16-bit unsigned integer.
614 | public void PutShort(short value)
615 | {
616 | byte[] bytes = BitConverter.GetBytes(value);
617 | WriteBigEndian(bytes);
618 | }
619 |
620 | ///
621 | /// Relative put method for writing an int value.
622 | /// Writes four bytes containing the given int value, in the current byte order, into this buffer at the current position, and then increments the position by four.
623 | ///
624 | /// The int value to be written.
625 | public void PutInt(int value)
626 | {
627 | byte[] bytes = BitConverter.GetBytes(value);
628 | //this.Write(bytes, 0, bytes.Length);
629 | WriteBigEndian(bytes);
630 | }
631 | ///
632 | /// Absolute put method for writing an int value.
633 | /// Writes four bytes containing the given int value, in the current byte order, into this buffer at the given index.
634 | ///
635 | /// The index at which the bytes will be written.
636 | /// The int value to be written.
637 | public void PutInt(int index, int value)
638 | {
639 | byte[] bytes = BitConverter.GetBytes(value);
640 | for (int i = bytes.Length - 1, j = 0; i >= 0; i--, j++)
641 | {
642 | this.Put(index + j, bytes[i]);
643 | }
644 | }
645 |
646 | ///
647 | /// Absolute put method for writing an int value.
648 | /// Writes four bytes containing the given int value, in the current byte order, into this buffer at the given index.
649 | ///
650 | /// The index at which the bytes will be written.
651 | /// The int value to be written.
652 | public void Put(int index, UInt32 value)
653 | {
654 | byte[] bytes = BitConverter.GetBytes(value);
655 | this.WriteBytes(index, bytes);
656 | }
657 |
658 | /*
659 | public void Put(UInt16 value)
660 | {
661 | byte[] bytes = BitConverter.GetBytes(value);
662 | this.Put(bytes);
663 | }
664 | */
665 |
666 | public void Put(int index, UInt16 value)
667 | {
668 | byte[] bytes = BitConverter.GetBytes(value);
669 | this.WriteBytes(index, bytes);
670 | }
671 |
672 | public int ReadUInt24()
673 | {
674 | byte[] bytes = this.ReadBytes(3);
675 | int value = bytes[0] << 16 | bytes[1] << 8 | bytes[2];
676 | return value;
677 | }
678 | ///
679 | /// Reads a 4-byte signed integer.
680 | ///
681 | /// The 4-byte signed integer.
682 | public int ReadReverseInt()
683 | {
684 | byte[] bytes = this.ReadBytes(4);
685 | int val = 0;
686 | val += bytes[3] << 24;
687 | val += bytes[2] << 16;
688 | val += bytes[1] << 8;
689 | val += bytes[0];
690 | return val;
691 | }
692 | ///
693 | /// Puts an in buffer stream onto an out buffer stream and returns the bytes written.
694 | ///
695 | ///
696 | ///
697 | ///
698 | ///
699 | public static int Put(ByteBuffer output, ByteBuffer input, int numBytesMax)
700 | {
701 | int limit = input.Limit;
702 | int numBytesRead = (numBytesMax > input.Remaining) ? input.Remaining : numBytesMax;
703 | /*
704 | input.Limit = (int)input.Position + numBytesRead;
705 | output.Put(input);
706 | input.Limit = limit;
707 | */
708 | output.Put(input, numBytesRead);
709 | return numBytesRead;
710 | }
711 | ///
712 | /// Write the buffer content to a file.
713 | ///
714 | ///
715 | public void Dump(string file)
716 | {
717 | using (FileStream fs = new FileStream(file, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
718 | {
719 | byte[] buffer = this.ToArray();
720 | fs.Write(buffer, 0, buffer.Length);
721 | fs.Close();
722 | }
723 | }
724 | }
725 | }
726 |
--------------------------------------------------------------------------------
/DataGateway/Common/DateTimeEx.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace JT808DataServer.Common
6 | {
7 | public class DateTimeEx
8 | {
9 | ///
10 | /// 获取系统时间戳-毫秒
11 | ///
12 | public static long CurrentTimeMillis
13 | {
14 | get
15 | {
16 | TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
17 | return Convert.ToInt64(ts.TotalSeconds * 1000);
18 | }
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Codec/JT808Decoder.cs:
--------------------------------------------------------------------------------
1 | using DataGateway.GPS.JT808.Megssages;
2 | using DataGateway.GPS.JT808.Messages;
3 | using DotNetty.Buffers;
4 | using JT808DataServer.Common;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Text;
8 |
9 | namespace DataGateway.GPS.JT808.Codec
10 | {
11 | public class JT808ProtoDecoder
12 | {
13 | public static byte FLAG_BYTE = 0x7e;
14 |
15 |
16 | ///
17 | /// 解码字节数组为JT808Message
18 | ///
19 | ///
20 | ///
21 | public static JT808Message Decode(byte[] bytes)
22 | {
23 | // Encoding.GetEncoding("GBK").GetBytes(value);
24 |
25 | ByteBuffer buffer = ByteBuffer.Wrap(bytes);
26 | byte headFlag = buffer.Get();
27 | buffer.Position = buffer.Capacity - 1;
28 | byte tailFlag = buffer.Get();
29 |
30 | // --> Check head flag 检查消息头/尾
31 | if (headFlag != FLAG_BYTE)
32 | {
33 | throw new Exception(
34 | "Parameter: buffer head flag byte is not " + FLAG_BYTE);
35 | }
36 | if (tailFlag != FLAG_BYTE)
37 | {
38 | throw new Exception(
39 | "Parameter: buffer tail flag byte is not " + FLAG_BYTE);
40 | }
41 |
42 | buffer.Position = 1;
43 | buffer.Limit = buffer.Capacity - 1;
44 |
45 | byte[] dataWithoutFlag = new byte[buffer.Capacity - 2];
46 | buffer.Read(dataWithoutFlag);
47 |
48 | // unescape - 反转义
49 | byte[] dataAfterUnescape = Unescape(dataWithoutFlag);
50 |
51 | // Validate checkCode - 验证校验码
52 | byte checkCode = dataAfterUnescape[dataAfterUnescape.Length - 1];
53 |
54 | byte[] dataToCheck = new byte[dataAfterUnescape.Length - 1];
55 | Array.Copy(dataAfterUnescape, 0, dataToCheck, 0, dataAfterUnescape.Length - 1);
56 |
57 |
58 | byte expectCheckCode = CheckCode(dataToCheck);
59 | if (checkCode != expectCheckCode)
60 | {
61 | throw new Exception(
62 | "Parameter: buffer check failed, expect-check-code="
63 | + expectCheckCode + ", actually-check-code=" + checkCode);
64 | }
65 |
66 | ByteBuffer dataAfterUnescapeBuffer = ByteBuffer.Wrap(dataAfterUnescape);
67 | JT808Message message = new JT808Message();
68 |
69 | // Decode head ----------------------------------- Begin
70 | // 开始头部解码
71 | JT808MessageHead head = new JT808MessageHead();
72 | // Message ID - 消息ID
73 | head.MessageId = dataAfterUnescapeBuffer.GetShort();
74 |
75 | // Message body attributes - 消息体属性
76 | head.MsgBodyAttr = Decode(dataAfterUnescapeBuffer.GetShort());
77 |
78 | // Terminal SimNo - 终端手机号
79 | byte[] mobileBytes = new byte[6];
80 | dataAfterUnescapeBuffer.Read(mobileBytes);
81 |
82 | head.TerminalId = Bcd6_2mobile(mobileBytes);
83 | head.MessageSerial = dataAfterUnescapeBuffer.GetShort();
84 |
85 | if (head.MsgBodyAttr.IsSplit)
86 | {
87 | MessageSplitInfo splitInfo = new MessageSplitInfo();
88 | splitInfo.Packages = dataAfterUnescapeBuffer.GetShort();
89 | splitInfo.PackageNo = dataAfterUnescapeBuffer.GetShort();
90 | head.SplitInfo = splitInfo;
91 | }
92 | message.MsgHeader = head;
93 | // Decode head ------------------------------------ End
94 | // 解码头部结束
95 |
96 | // Message body
97 | // 消息体
98 |
99 | int bodyLength = head.MsgBodyAttr.MsgBodyLength;
100 | byte[] body = new byte[bodyLength];
101 | dataAfterUnescapeBuffer.Read(body);
102 | message.MsgBody = body;
103 |
104 | // Check Code - 校验码
105 | message.CheckCode = checkCode;
106 | return message;
107 | }
108 |
109 |
110 | ///
111 | /// 6字节的BCD码转为终端手机号字符串
112 | ///
113 | ///
114 | ///
115 | public static string Bcd6_2mobile(byte[] bytes)
116 | {
117 |
118 | StringBuilder mobile = new StringBuilder();
119 | for (int i = 0; i < 6; i++)
120 | {
121 | int n = Bcd2decimal(bytes[i]);
122 | if (i != 0 && n < 10)
123 | {
124 | mobile.Append("0");
125 | }
126 | mobile.Append(Bcd2decimal(bytes[i]));
127 | }
128 |
129 | return mobile.ToString();
130 | }
131 |
132 |
133 | ///
134 | /// 10进制数转BCD码
135 | ///
136 | ///
137 | ///
138 | public static byte Num2BCD(int n)
139 | {
140 | return (byte)(((n / 10) << 4) + (n % 10));
141 | }
142 |
143 | ///
144 | /// BCD码转10进制数
145 | ///
146 | ///
147 | ///
148 | public static int Bcd2decimal(byte bcd)
149 | {
150 | return (bcd >> 4 & 0x0F) * 10 + (bcd & 0x0F);
151 | }
152 |
153 |
154 | ///
155 | /// 解码为对象
156 | ///
157 | ///
158 | ///
159 | public static JT808MessageBodyAttr Decode(short _2Bytes)
160 | {
161 |
162 | JT808MessageBodyAttr attr = new JT808MessageBodyAttr();
163 |
164 | // isSpilt ?
165 | int isSplit = _2Bytes >> 13 & 0x1;
166 | if (isSplit == 1)
167 | {
168 | attr.IsSplit = true;
169 | }
170 |
171 | // Encrypt type
172 | int encryptTypeVal = _2Bytes >> 10 & 0x1;
173 | if (encryptTypeVal == 1)
174 | {
175 | attr.EncryptionType = 1;
176 | }
177 | else
178 | {
179 | attr.EncryptionType = 0;
180 | }
181 |
182 | // Body length
183 | int bodyLen = _2Bytes & 0x3ff;
184 | attr.MsgBodyLength = bodyLen;
185 |
186 | return attr;
187 | }
188 |
189 | ///
190 | /// 反转义,规则如下:
191 | /// 0x7d 0x02 -> 0x7e
192 | /// 0x7d 0x01 -> 0x7d
193 | ///
194 | ///
195 | ///
196 | public static byte[] Unescape(byte[] target)
197 | {
198 |
199 | int resultLen = target.Length;
200 | foreach (byte b in target)
201 | {
202 | if (b == 0x7d)
203 | {
204 | resultLen--;
205 | }
206 | }
207 |
208 | ByteBuffer buffer = ByteBuffer.Allocate(resultLen);
209 | bool lastIs7D = false;
210 | foreach (byte b in target)
211 | {
212 | if (b == 0x7d)
213 | {
214 | lastIs7D = true;
215 | continue;
216 | }
217 |
218 | if (lastIs7D == true)
219 | {
220 | if (b == 0x01)
221 | {
222 | buffer.Put((byte)0x7d);
223 | }
224 | else if (b == 0x02)
225 | {
226 | buffer.Put((byte)0x7e);
227 | }
228 | lastIs7D = false;
229 | continue;
230 | }
231 |
232 | buffer.Put(b);
233 | }
234 |
235 | return buffer.Array();
236 | }
237 |
238 | ///
239 | /// 计算校验码
240 | ///
241 | ///
242 | ///
243 | public static byte CheckCode(byte[] data)
244 | {
245 |
246 | byte checkCode = 0;
247 |
248 | for (int i = 0; i < data.Length; i++)
249 | {
250 | if (i == 0)
251 | {
252 | checkCode = data[i];
253 | continue;
254 | }
255 | checkCode ^= data[i];
256 | }
257 | return checkCode;
258 | }
259 |
260 |
261 | ///
262 | /// 按照JT/T808协议, 对消息进行转义,规则如下:
263 | /// 0x7e -> 0x7d 0x02
264 | /// 0x7d -> 0x7d 0x01
265 | ///
266 | ///
267 | ///
268 | public static byte[] Escape(byte[] target)
269 | {
270 |
271 | int resultLen = 0;
272 | foreach (byte b in target)
273 | {
274 | if (b == 0x7e || b == 0x7d)
275 | {
276 | resultLen += 2;
277 | continue;
278 | }
279 | resultLen++;
280 | }
281 |
282 | ByteBuffer buffer = ByteBuffer.Allocate(resultLen);
283 | foreach (byte b in target)
284 | {
285 | if (b == 0x7e)
286 | {
287 | buffer.Put((byte)0x7d);
288 | buffer.Put((byte)0x02);
289 | continue;
290 | }
291 | if (b == 0x7d)
292 | {
293 | buffer.Put((byte)0x7d);
294 | buffer.Put((byte)0x01);
295 | continue;
296 | }
297 | buffer.Put(b);
298 | }
299 |
300 | return buffer.Array();
301 | }
302 |
303 | ///
304 | /// 手机号字符串转6字节的BCD码 Mobile No. to 6 bytes BCD, mobile 12 chars
305 | ///
306 | ///
307 | ///
308 | public static byte[] Mobile2bcd6(string mobile)
309 | {
310 | ByteBuffer buffer = ByteBuffer.Allocate(6);
311 | long l = long.Parse(mobile);
312 |
313 | buffer.Put(Num2BCD((int)(l / 10000000000L)));
314 | l %= 10000000000L;
315 | buffer.Put(Num2BCD((int)(l / 100000000L)));
316 | l %= 100000000L;
317 | buffer.Put(Num2BCD((int)(l / 1000000L)));
318 | l %= 1000000L;
319 | buffer.Put(Num2BCD((int)(l / 10000L)));
320 | l %= 10000L;
321 | buffer.Put(Num2BCD((int)(l / 100L)));
322 | l %= 100L;
323 | buffer.Put(Num2BCD((int)l));
324 |
325 | return buffer.Array();
326 | }
327 |
328 | }
329 | }
330 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Constant/JT808Constant.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DataGateway.GPS.JT808.Constant
6 | {
7 | public class JT808Constant
8 | {
9 | public static short MAX_MSG_BODY_LENGTH = 1023;
10 |
11 | public static short MAX_MOBILE_LENGTH = 12;
12 |
13 |
14 | public static Encoding STRING_ENCODING = Encoding.GetEncoding("GBK");
15 |
16 | ///
17 | /// 标识位
18 | ///
19 | public static byte PKG_DELIMITER = 0x7e;
20 |
21 | ///
22 | /// 客户端15分钟后无动作,服务器主动断开连接
23 | ///
24 | public static short TCP_CLIENT_IDLE_MINUTES = 30;
25 |
26 | ///
27 | /// 终端通用应答
28 | ///
29 | public static short MSG_ID_TERMINAL_COMMON_RESP = 0x0001;
30 |
31 | ///
32 | /// 终端心跳
33 | ///
34 | public static short MSG_ID_TERMINAL_HEART_BEAT = 0x0002;
35 |
36 | ///
37 | /// 终端注册
38 | ///
39 | public static short MSG_ID_TERMINAL_REGISTER = 0x0100;
40 |
41 | ///
42 | /// 终端注销
43 | ///
44 | public static short MSG_ID_TERMINAL_LOG_OUT = 0x0003;
45 |
46 | ///
47 | /// 终端鉴权
48 | ///
49 | public static short MSG_ID_TERMINAL_AUTHENTICATION = 0x0102;
50 |
51 |
52 | ///
53 | /// 位置信息汇报
54 | ///
55 | public static short MSG_ID_TERMINAL_LOCATION_INFO_UPLOAD = 0x0200;
56 |
57 | ///
58 | /// 胎压数据透传
59 | ///
60 | public static short MSG_ID_TERMINAL_TRANSMISSION_TYRE_PRESSURE = 0x0600;
61 |
62 | ///
63 | /// 查询终端参数应答
64 | ///
65 | public static short MSG_ID_TERMINAL_PARAM_QUERY_RESP = 0x0104;
66 |
67 | ///
68 | /// 平台通用应答
69 | ///
70 | public static int CMD_COMMON_RESP = 0x8001;
71 |
72 | ///
73 | /// 终端注册应答
74 | ///
75 | public static int CMD_TERMINAL_REGISTER_RESP = 0x8100;
76 |
77 | ///
78 | /// 设置终端参数
79 | ///
80 | public static int CMD_TERMINAL_PARAM_SETTINGS = 0X8103;
81 |
82 | ///
83 | /// 查询终端参数
84 | ///
85 | public static int CMD_TERMINAL_PARAM_QUERY = 0x8104;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Constant/MessageResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DataGateway.GPS.JT808.Constant
6 | {
7 | public class MessageResult
8 | {
9 | ///
10 | /// 成功
11 | ///
12 | public static byte Success = 0;
13 |
14 | ///
15 | /// 失败
16 | ///
17 | public static byte Failure = 1;
18 |
19 | ///
20 | /// 消息错误
21 | ///
22 | public static byte Msg_error = 2;
23 |
24 | ///
25 | /// 不支持的消息
26 | ///
27 | public static byte Unsupported = 3;
28 |
29 | ///
30 | /// Warnning_msg_ack
31 | ///
32 | public static byte Warnning_msg_ack = 4;
33 |
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Data/LocationInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DataGateway.GPS.JT808.Data
6 | {
7 | ///
8 | /// 位置信息
9 | ///
10 | [Serializable]
11 | public class LocationInfo
12 | {
13 | ///
14 | /// 报警标志
15 | ///
16 | public AlarmInfo AlarmState { get; set; }
17 |
18 | ///
19 | /// 状态信息
20 | ///
21 | public WorkStateInfo StateInfo { get; set; }
22 |
23 | ///
24 | /// 经度
25 | ///
26 | public Double Lon { get; set; }
27 |
28 | ///
29 | /// 纬度
30 | ///
31 | public Double Lat { get; set; }
32 |
33 | ///
34 | /// 偏移经度
35 | ///
36 | public Double ShiftLon { get; set; }
37 |
38 | ///
39 | /// 偏移纬度
40 | ///
41 | public Double ShiftLat { get; set; }
42 |
43 | ///
44 | /// 海拔高度,单位为米(m)
45 | ///
46 | public Double Altitude { get; set; }
47 |
48 | ///
49 | /// 速度 km/h
50 | ///
51 | public Double Speed { get; set; }
52 |
53 | ///
54 | /// 方向 0-359,正北为 0,顺时针
55 | ///
56 | public int Direction { get; set; }
57 |
58 | ///
59 | /// gps时间
60 | ///
61 | public string GpsTime { get; set; }
62 | }
63 |
64 | ///
65 | /// 报警状态位
66 | ///
67 | public class AlarmInfo
68 | {
69 | ///
70 | /// 超速报警
71 | ///
72 | public bool OverSpeed { get; set; }
73 |
74 | ///
75 | /// GNSS 模块发生故障
76 | ///
77 | public bool GnssFault { get; set; }
78 |
79 |
80 | ///
81 | /// 终端主电源欠压
82 | ///
83 | public bool PowerLow { get; set; }
84 |
85 | ///
86 | /// 终端主电源掉电
87 | ///
88 | public bool PowerOff { get; set; }
89 |
90 | }
91 |
92 | ///
93 | /// 状态位
94 | ///
95 | public class WorkStateInfo
96 | {
97 | ///
98 | /// ACC状态
99 | ///
100 | public bool AccOn { get; set; }
101 |
102 | ///
103 | /// 导航状态
104 | ///
105 | public bool Navigation { get; set; }
106 |
107 | ///
108 | /// 0:北纬;1:南纬
109 | ///
110 | public int Latitude_N_S { get; set; }
111 |
112 | ///
113 | /// 0:东经;1:西经
114 | ///
115 | public int Longitude_E_W { get; set; }
116 |
117 | }
118 |
119 | }
120 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Data/TerminalRegInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace DataGateway.GPS.JT808.Data
3 | {
4 | ///
5 | /// 终端注册信息-消息ID:0x0100 上传
6 | ///
7 | [Serializable]
8 | public class TerminalRegInfo
9 | {
10 | ///
11 | /// 省域ID
12 | ///
13 | public int ProvinceId { get; set; }
14 |
15 | ///
16 | /// 市县域ID
17 | ///
18 | public int CityId{ get; set; }
19 |
20 | ///
21 | /// 制造商ID,终端制造商编码
22 | ///
23 | public string ManufacturerId{ get; set; }
24 |
25 | ///
26 | /// 终端型号 由制造商自行定义
27 | ///
28 | public string TerminalType{ get; set; }
29 |
30 | ///
31 | /// 终端ID由大写字母和数字组成-制造商自行定义
32 | ///
33 | public string TerminalId{ get; set; }
34 |
35 | ///
36 | /// 车牌颜色(BYTE) 车牌颜色,按照 JT/T415-2006 的 5.4.12 未上牌时,取值为0
37 | /// 0 未上车牌
38 | /// 1 蓝色
39 | /// 2 黄色
40 | /// 3 黑色
41 | /// 4 白色
42 | /// 9 其他
43 | ///
44 | public int LicensePlateColor{ get; set; }
45 |
46 |
47 | ///
48 | /// 车牌 公安交通管理部门颁发的机动车号牌
49 | ///
50 | public string LicensePlate{ get; set; }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Handler/JT808ProInHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using DotNetty.Buffers;
3 | using DotNetty.Transport.Channels;
4 | using DataGateway.GPS.JT808.Megssages;
5 | using DataGateway.GPS.JT808.Codec;
6 | using DataGateway.GPS.JT808.Service;
7 | using DotNetty.Handlers.Timeout;
8 | using DataGateway.GPS.JT808.Model;
9 | using DataGateway.GPS.JT808.Constant;
10 | using DataGateway.GPS.JT808.Messages;
11 |
12 | namespace DataGateway.GPS.JT808.Handler
13 | {
14 | public class JT808ProInHandler : ChannelHandlerAdapter
15 | {
16 | private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
17 | private TerminalMsgProcessService msgProcessService;
18 | private SessionManager sessionManager;
19 |
20 | public JT808ProInHandler()
21 | {
22 | sessionManager = SessionManager.Instance;
23 | msgProcessService = new TerminalMsgProcessService();
24 | }
25 |
26 | // 重写基类的方法,当消息到达时触发,这里收到消息后,在控制台输出收到的内容,并原样返回了客户端
27 | public override void ChannelRead(IChannelHandlerContext context, object message)
28 | {
29 |
30 | try
31 | {
32 | var buf = message as IByteBuffer;
33 | // 读取完整消息到字节数组
34 | int remaining = buf.ReadableBytes;
35 | byte[] messageBytes = new byte[remaining];
36 | buf.GetBytes(0, messageBytes);
37 |
38 | // 解析消息字节数组为JT808Message对象
39 | JT808Message result = JT808ProtoDecoder.Decode(messageBytes);
40 |
41 |
42 | // 网关接收数据时间
43 | //string gatewaytime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
44 |
45 | //消息正文
46 | //byte[] cmdconent = result.MsgBody;
47 |
48 | result.channel = context;
49 | msgProcessService.processMessageData(result);
50 | }
51 | catch (Exception ex)
52 | {
53 | logger.Error(ex, "解析数据时出错{0}",ex.Message);
54 | }
55 | }
56 |
57 |
58 | ///
59 | /// 捕获异常,客户端意外断开链接,也会触发
60 | ///
61 | ///
62 | ///
63 | public override void ExceptionCaught(IChannelHandlerContext context, Exception exception)
64 | {
65 | logger.Error("发生异常:{0}", exception.Message);
66 | }
67 |
68 | public override void ChannelActive(IChannelHandlerContext ctx)
69 | {
70 | Session session = Session.BuildSession(ctx.Channel);
71 | sessionManager.SessionAdd(session.Id, session);
72 | logger.Info("终端连接:{0}", ctx.Channel);
73 | }
74 |
75 | public override void ChannelInactive(IChannelHandlerContext ctx) {
76 | string sessionId = ctx.Channel.Id.AsLongText();
77 | Session session = sessionManager.FindBySessionId(sessionId);
78 | this.sessionManager.SessionRemove(sessionId);
79 | logger.Info("终端断开连接:{0}", ctx.Channel);
80 | }
81 |
82 |
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Messages/JT808Message.cs:
--------------------------------------------------------------------------------
1 | using DataGateway.GPS.JT808.Codec;
2 | using DataGateway.GPS.JT808.Constant;
3 | using DotNetty.Transport.Channels;
4 | using JT808DataServer.Common;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Text;
8 |
9 | namespace DataGateway.GPS.JT808.Megssages
10 | {
11 | public class JT808Message
12 | {
13 | ///
14 | /// 16byte 消息头
15 | ///
16 | public JT808MessageHead MsgHeader { get; set; }
17 |
18 | ///
19 | /// 消息体字节数组
20 | ///
21 | public byte[] MsgBody { get; set; }
22 |
23 | ///
24 | /// 校验码 1byte
25 | ///
26 | public int CheckCode { get; set; }
27 |
28 | ///
29 | /// 将消息按JT/T 808协议进行编码为字节数组
30 | ///
31 | ///
32 | public byte[] Encode()
33 | {
34 | if (MsgHeader == null)
35 | {
36 | throw new Exception("Field: msgHead cannot be null.");
37 | }
38 |
39 | // 消息头编码
40 | byte[] msgHeadBytes = MsgHeader.Encode();
41 |
42 | // body
43 | byte[] msgBodyBytes = null;
44 | if (MsgBody != null)
45 | {
46 | msgBodyBytes = MsgBody;
47 | }
48 |
49 | // 构建消息(不包含校验码和头尾标识)
50 | byte[] message = null;
51 | if (msgBodyBytes != null)
52 | {
53 | ByteBuffer msgbuf = ByteBuffer.Allocate(
54 | msgHeadBytes.Length + msgBodyBytes.Length);
55 | msgbuf.Put(msgHeadBytes);
56 | msgbuf.Put(msgBodyBytes);
57 | message = msgbuf.Array();
58 | }
59 | else
60 | {
61 | message = msgHeadBytes;
62 | }
63 |
64 | // 计算校验码
65 | byte checkCode = JT808ProtoDecoder.CheckCode(message);
66 | ByteBuffer checkedBuffer = ByteBuffer.Allocate(message.Length + 1);
67 | checkedBuffer.Put(message);
68 | checkedBuffer.Put(checkCode);
69 | byte[] checkedMessage = checkedBuffer.Array();
70 |
71 | // 转义
72 | byte[] escapedMessage = JT808ProtoDecoder.Escape(checkedMessage);
73 |
74 | // 增加标识位
75 | ByteBuffer buffer = ByteBuffer.Allocate(escapedMessage.Length + 2);
76 | buffer.Put(JT808Constant.PKG_DELIMITER);
77 | buffer.Put(escapedMessage);
78 | buffer.Put(JT808Constant.PKG_DELIMITER);
79 |
80 | return buffer.Array();
81 | }
82 |
83 |
84 | ///
85 | /// 会话正文
86 | ///
87 | public IChannelHandlerContext channel { get; set; }
88 |
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Messages/JT808MessageBodyAttr.cs:
--------------------------------------------------------------------------------
1 | using DataGateway.GPS.JT808.Constant;
2 | using JT808DataServer.Common;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | namespace DataGateway.GPS.JT808.Messages
8 | {
9 | ///
10 | /// JT808消息体属性
11 | ///
12 | public class JT808MessageBodyAttr
13 | {
14 | ///
15 | /// 消息体长度
16 | /// 10 bits
17 | ///
18 | public int MsgBodyLength { get; set; }
19 |
20 | ///
21 | /// 数据加密方式 NON(0), RSA(1);
22 | ///
23 | public int EncryptionType { get; set; }
24 |
25 | ///
26 | /// 是否分包
27 | /// Not a complete package, it's split. 1 bit
28 | ///
29 | public bool IsSplit { get; set; }
30 |
31 | ///
32 | /// 保留数据
33 | /// 2 bits
34 | ///
35 | public int Reserve { get; set; }
36 |
37 | ///
38 | /// 编码为字节数组
39 | ///
40 | ///
41 | public byte[] Encode()
42 | {
43 |
44 | int init = 0x0;
45 |
46 | // is package split
47 | if (IsSplit)
48 | {
49 | init = (init | 0x1) << 13;
50 | }
51 |
52 | // encrypt type
53 | init = init | (EncryptionType << 10);
54 |
55 | // message body length
56 | if (MsgBodyLength> JT808Constant.MAX_MSG_BODY_LENGTH)
57 | {
58 | throw new Exception("Field: msgBodyLength="
59 | + MsgBodyLength + ", but max allowable values is "
60 | + JT808Constant.MAX_MSG_BODY_LENGTH + ".");
61 | }
62 |
63 | init = init | MsgBodyLength;
64 |
65 | ByteBuffer buffer = ByteBuffer.Allocate(2);
66 | buffer.PutShort((short)init);
67 |
68 | return buffer.Array();
69 | }
70 |
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Messages/JT808MessageHead.cs:
--------------------------------------------------------------------------------
1 | using DataGateway.GPS.JT808.Codec;
2 | using DataGateway.GPS.JT808.Constant;
3 | using DataGateway.GPS.JT808.Messages;
4 | using JT808DataServer.Common;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Text;
8 |
9 | namespace DataGateway.GPS.JT808.Megssages
10 | {
11 | ///
12 | /// JT/T808协议消息头
13 | ///
14 | public class JT808MessageHead
15 | {
16 | ///
17 | /// 消息ID
18 | ///
19 | public short MessageId { get; set; }
20 |
21 | ///
22 | /// 消息体属性
23 | ///
24 | public JT808MessageBodyAttr MsgBodyAttr { get; set; }
25 |
26 |
27 | ///
28 | /// 终端ID-上传的SIM卡号
29 | ///
30 | public string TerminalId { get; set; }
31 |
32 | ///
33 | /// 流水号
34 | ///
35 | public short MessageSerial { get; set; }
36 |
37 |
38 | ///
39 | /// 消息包封装项
40 | /// If msgBodyAttr.isSplit=true, then it not null.
41 | ///
42 | public MessageSplitInfo SplitInfo { get; set; }
43 |
44 | ///
45 | /// 编码消息头为字节数组
46 | ///
47 | ///
48 | public byte[] Encode()
49 | {
50 |
51 | int capacity = 12;
52 | byte[] splitInfoBytes = null;
53 | if (SplitInfo != null)
54 | {
55 | splitInfoBytes = SplitInfo.Encode();
56 | capacity += splitInfoBytes.Length;
57 | }
58 |
59 | if (MsgBodyAttr == null)
60 | {
61 | throw new Exception("Field: msgBodyAttr cannot be null.");
62 | }
63 |
64 | ByteBuffer buffer = ByteBuffer.Allocate(capacity);
65 | buffer.PutShort(MessageId);
66 | buffer.Put(MsgBodyAttr.Encode());
67 |
68 | // mobile
69 | if (TerminalId.Length > JT808Constant.MAX_MOBILE_LENGTH)
70 | {
71 | throw new Exception(
72 | "Field: mobile=" + TerminalId
73 | + ", but max allowable value is "
74 | + JT808Constant.MAX_MOBILE_LENGTH + ".");
75 | }
76 |
77 |
78 | buffer.Put(JT808ProtoDecoder.Mobile2bcd6(TerminalId));
79 | buffer.PutShort(this.MessageSerial);
80 | if (splitInfoBytes != null)
81 | {
82 | buffer.Put(splitInfoBytes);
83 | }
84 |
85 | return buffer.Array();
86 | }
87 |
88 |
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Messages/MessageSplitInfo.cs:
--------------------------------------------------------------------------------
1 | using JT808DataServer.Common;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace DataGateway.GPS.JT808.Messages
7 | {
8 | public class MessageSplitInfo
9 | {
10 | ///
11 | /// 消息总包数
12 | ///
13 | public short Packages { get; set; }
14 |
15 | ///
16 | /// 包序号,从1开始
17 | ///
18 | public short PackageNo { get; set; }
19 |
20 | ///
21 | /// 编码为字节数组
22 | ///
23 | ///
24 | public byte[] Encode()
25 | {
26 | ByteBuffer buffer = ByteBuffer.Allocate(4);
27 | buffer.PutShort(Packages);
28 | buffer.PutShort(PackageNo);
29 | return buffer.Array();
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Model/CommonPlatformResp.cs:
--------------------------------------------------------------------------------
1 | using DataGateway.GPS.JT808.Constant;
2 | using JT808DataServer.Common;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | namespace DataGateway.GPS.JT808.Model
8 | {
9 | ///
10 | /// 平台通用应答
11 | ///
12 | public class CommonPlatformResp : PlatformResp
13 | {
14 | ///
15 | /// byte[2-3] 应答ID 对应的终端消息的ID
16 | ///
17 | public short ReplyId { get; set; }
18 |
19 | ///
20 | /// 响应码
21 | /// 0:成功∕确认
22 | /// 1:失败
23 | /// 2:消息有误
24 | /// 3:不支持
25 | /// 4:报警处理确认
26 | ///
27 | public byte ReplyCode { get; set; }
28 |
29 | public CommonPlatformResp() {
30 |
31 | }
32 |
33 | ///
34 | /// 构造函数
35 | ///
36 | /// 应答流水号
37 | /// 终端消息的ID
38 | /// 响应码
39 | public CommonPlatformResp(short replyId, byte replyCode)
40 | {
41 | ReplyId = replyId;
42 | ReplyCode = replyCode;
43 | }
44 |
45 | public override byte[] Encode()
46 | {
47 | ByteBuffer buffer = ByteBuffer.Allocate(5);
48 | buffer.PutShort(ReplySerial);
49 | buffer.PutShort(ReplyId);
50 | buffer.Put(ReplyCode);
51 | return buffer.Array();
52 | }
53 |
54 | public override short GetMessageId()
55 | {
56 | return (short) JT808Constant.CMD_COMMON_RESP;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Model/PlatformResp.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DataGateway.GPS.JT808.Model
6 | {
7 | ///
8 | /// 平台应答类
9 | ///
10 | public abstract class PlatformResp
11 | {
12 | ///
13 | /// 终端ID
14 | ///
15 | public string TerminalId { get; set; }
16 |
17 | ///
18 | /// 应答流水号
19 | ///
20 | public short ReplySerial { get; set; }
21 |
22 | ///
23 | /// 编码
24 | ///
25 | ///
26 | public abstract byte[] Encode();
27 |
28 |
29 | public abstract short GetMessageId();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Model/ResponseData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DataGateway.GPS.JT808.Model
6 | {
7 | public class ResponseData
8 | {
9 | public string TerminalID { get; set; }
10 | public long Time { get; set; }
11 | public int CmdID { get; set; }
12 | public int CmdSerialNo { get; set; }
13 | public byte[] MsgBody { get; set; }
14 |
15 |
16 | public ResponseData()
17 | {
18 | }
19 |
20 | public ResponseData(String terminalID, long time, int cmdID, int cmdSerialNo, byte[] msgBody)
21 | {
22 | TerminalID = terminalID;
23 | Time = time;
24 | CmdID = cmdID;
25 | CmdSerialNo = cmdSerialNo;
26 | MsgBody = msgBody;
27 | }
28 |
29 | ///
30 | /// 获取时间戳
31 | ///
32 | ///
33 | public long GetTimeStamp()
34 | {
35 | TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
36 | return (long)ts.TotalSeconds;
37 | }
38 |
39 |
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Model/TerminalRegPlatformResp.cs:
--------------------------------------------------------------------------------
1 | using DataGateway.GPS.JT808.Constant;
2 | using JT808DataServer.Common;
3 |
4 | namespace DataGateway.GPS.JT808.Model
5 | {
6 | ///
7 | /// 终端注册应答
8 | ///
9 | public class TerminalRegPlatformResp : PlatformResp
10 | {
11 | ///
12 | /// 响应码
13 | /// 0:SUCCESS
14 | /// 1:VEH_REGISTERED
15 | /// 2:VEH_NOT_FOUND
16 | /// 3:TERM_registered
17 | /// 4:TERM_NOT_FOUND
18 | ///
19 | public byte ReplyCode { get; set; }
20 |
21 | ///
22 | /// 鉴权码
23 | ///
24 | public string AuthCode { get; set; }
25 |
26 | public override byte[] Encode()
27 | {
28 |
29 | if (AuthCode == null)
30 | {
31 | AuthCode = "";
32 | }
33 |
34 |
35 | byte[] authCodeBytes = JT808Constant.STRING_ENCODING.GetBytes(AuthCode);
36 |
37 | ByteBuffer buffer = ByteBuffer.Allocate(3 + authCodeBytes.Length);
38 | buffer.PutShort(ReplySerial);
39 | buffer.Put(ReplyCode);
40 | buffer.Put(authCodeBytes);
41 | return buffer.Array();
42 | }
43 |
44 | public override short GetMessageId()
45 | {
46 | return (short)JT808Constant.CMD_TERMINAL_REGISTER_RESP;
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Service/BaseMsgProcessService.cs:
--------------------------------------------------------------------------------
1 | using DataGateway.gps.server;
2 | using DotNetty.Transport.Channels;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | namespace DataGateway.GPS.JT808.Service
8 | {
9 | public class BaseMsgProcessService
10 | {
11 | protected static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
12 | protected SessionManager sessionManager;
13 |
14 | public BaseMsgProcessService()
15 | {
16 | sessionManager = SessionManager.Instance;
17 | }
18 |
19 | ///
20 | /// 获取应答流水号
21 | ///
22 | ///
23 | ///
24 | ///
25 | protected short GetFlowId(IChannel channel, short defaultValue)
26 | {
27 | Session session = sessionManager.FindBySessionId(Session.BuildId(channel));
28 | if (session == null)
29 | {
30 | return defaultValue;
31 | }
32 |
33 | return session.CurrentFlowId;
34 | }
35 |
36 | ///
37 | /// 获取应答流水号
38 | ///
39 | ///
40 | ///
41 | protected short GetFlowId(IChannel channel)
42 | {
43 | return GetFlowId(channel, 0);
44 | }
45 |
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Service/Session.cs:
--------------------------------------------------------------------------------
1 | using DotNetty.Transport.Channels;
2 | using System;
3 | using System.Net;
4 | using System.Text;
5 |
6 | namespace DataGateway.GPS.JT808.Service
7 | {
8 | public class Session
9 | {
10 | ///
11 | /// session id
12 | ///
13 | public string Id { get; set; }
14 |
15 | ///
16 | /// 终端上传的SIM卡号
17 | ///
18 | public string TerminalPhone { get; set; }
19 |
20 | public IChannel Channel { get; set; }
21 |
22 | ///
23 | /// 是否授权
24 | ///
25 | public bool IsAuthenticated { get; set; }
26 |
27 | // 消息流水号 word(16) 按发送顺序从 0 开始循环累加
28 | private short _currentFlowId = 0;
29 |
30 | public short CurrentFlowId
31 | {
32 | get
33 | {
34 | if (_currentFlowId == short.MaxValue)
35 | _currentFlowId = 0;
36 |
37 | return _currentFlowId++;
38 | }
39 | }
40 |
41 | // private ChannelGroup channelGroup = new
42 | // DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
43 | // 客户端上次的连接时间,该值改变的情况:
44 | // 1. terminal --> server 心跳包
45 | // 2. terminal --> server 数据包
46 | public long LastCommunicateTimeStamp { get; set; }
47 |
48 |
49 | public static string BuildId(IChannel channel)
50 | {
51 | return channel.Id.AsLongText();
52 | }
53 |
54 | public static Session BuildSession(IChannel channel)
55 | {
56 | return BuildSession(channel, null);
57 | }
58 |
59 | public static Session BuildSession(IChannel channel, string phone)
60 | {
61 | Session session = new Session();
62 | session.Channel = channel;
63 | session.Id = BuildId(channel);
64 | session.TerminalPhone = phone;
65 |
66 | session.LastCommunicateTimeStamp = DateTime.Now.Millisecond;
67 | return session;
68 | }
69 |
70 | public EndPoint getRemoteAddr()
71 | {
72 | return Channel.RemoteAddress;
73 | }
74 |
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Service/SessionManager.cs:
--------------------------------------------------------------------------------
1 | using DotNetty.Transport.Channels;
2 | using System;
3 | using System.Collections.Concurrent;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | namespace DataGateway.GPS.JT808.Service
8 | {
9 | public sealed class SessionManager
10 | {
11 | ///
12 | /// Netty生成的sessionID和Session的对应关系
13 | /// key = seession id
14 | /// value = Session
15 | ///
16 | private ConcurrentDictionary SessionIdMap = new ConcurrentDictionary();
17 |
18 | ///
19 | /// 终端手机号和netty生成的sessionID的对应关系
20 | /// key = 手机号
21 | /// value = seession id
22 | ///
23 | private ConcurrentDictionary PhoneMap = new ConcurrentDictionary();
24 |
25 | private static volatile SessionManager instance = null;
26 | private static readonly object syncRoot = new object();
27 | private static readonly object InLock = new object();
28 | private static readonly object OutLock = new object();
29 | private static readonly object FindLock = new object();
30 |
31 |
32 |
33 | private SessionManager() { }
34 |
35 | public static SessionManager Instance
36 | {
37 | get
38 | {
39 | if (instance == null)
40 | {
41 | lock (syncRoot)
42 | {
43 | if (instance == null)
44 | {
45 | instance = new SessionManager();
46 | }
47 | }
48 | }
49 | return instance;
50 | }
51 | }
52 |
53 | ///
54 | /// 会话注册
55 | ///
56 | ///
57 | ///
58 | public void SessionAdd(string sessionid, Session session)
59 | {
60 | lock (InLock)
61 | {
62 | try
63 | {
64 |
65 | if (session.TerminalPhone != null && session.TerminalPhone.Trim().Length > 0)
66 | {
67 | PhoneMap.AddOrUpdate(session.TerminalPhone, session.Id, (key, value) => { return value = session.Id; });
68 | }
69 | SessionIdMap.AddOrUpdate(sessionid, session, (key, value) => { return value = session; });
70 | }
71 | catch (Exception ex)
72 | {
73 | Console.WriteLine("Session Add Exception," + ex.Message);
74 | }
75 | }
76 | }
77 |
78 | ///
79 | /// 会话查找
80 | ///
81 | ///
82 | ///
83 | public Session FindBySessionId(string sessionid)
84 | {
85 | lock (FindLock)
86 | {
87 | Session session = null;
88 | try
89 | {
90 | SessionIdMap.TryGetValue(sessionid, out session);
91 | }
92 | catch (Exception ex)
93 | {
94 | Console.WriteLine("Session Find Exception," + ex.Message);
95 | }
96 | return session;
97 | }
98 | }
99 |
100 | ///
101 | /// 会话移除
102 | ///
103 | ///
104 | ///
105 | public void SessionRemove(string sessionId)
106 | {
107 | lock (OutLock)
108 | {
109 | if (sessionId == null)
110 | return;
111 |
112 | try
113 | {
114 | Session session = null;
115 | SessionIdMap.TryRemove(sessionId, out session);
116 |
117 | if (session == null)
118 | return;
119 |
120 | string sessionid;
121 | if (session.TerminalPhone != null)
122 | PhoneMap.TryRemove(session.TerminalPhone, out sessionid);
123 |
124 | }
125 | catch (Exception ex)
126 | {
127 | Console.WriteLine("Session Remove Exception," + ex.Message);
128 | }
129 | }
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Service/TerminalMsgProcessService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using DotNetty.Transport.Channels;
3 | using Newtonsoft.Json;
4 | using DataGateway.GPS.JT808.Constant;
5 | using DataGateway.GPS.JT808.Megssages;
6 | using DataGateway.GPS.JT808.Messages;
7 | using DataGateway.GPS.JT808.Model;
8 | using DataGateway.GPS.JT808.Data;
9 | using DataGateway.GPS.JT808.Util;
10 | using DotNetty.Buffers;
11 | using System.Text;
12 | using JT808DataServer.Common;
13 |
14 | namespace DataGateway.GPS.JT808.Service
15 | {
16 | public class TerminalMsgProcessService : BaseMsgProcessService
17 | {
18 |
19 | public TerminalMsgProcessService()
20 | {
21 | }
22 |
23 |
24 | public void processMessageData(JT808Message req)
25 | {
26 | JT808MessageHead header = req.MsgHeader;
27 | // 1. 终端心跳-消息体为空 ==> 平台通用应答
28 | if (header.MessageId == JT808Constant.MSG_ID_TERMINAL_HEART_BEAT)
29 | {
30 | logger.Info("<<<<<[终端心跳],phone={0},flowid={1}", header.TerminalId, header.MessageSerial);
31 | ProcessCommonResponse(req);
32 | }//2. 终端注册 ==> 终端注册应答
33 | else if (header.MessageId == JT808Constant.MSG_ID_TERMINAL_REGISTER)
34 | {
35 | ProcessTerminalRegist(req);
36 | logger.Info(">>>>>[终端注册],终端ID={0},流水号={1}", header.TerminalId, header.MessageSerial);
37 |
38 | }//3.终端鉴权 ==> 平台通用应答
39 | else if (header.MessageId == JT808Constant.MSG_ID_TERMINAL_AUTHENTICATION)
40 | {
41 | logger.Info(">>>>>[终端鉴权],终端ID={0},流水号={1}", header.TerminalId, header.MessageSerial);
42 | ProcessCommonResponse(req);
43 | }//4.终端注销(终端注销数据消息体为空) ==> 平台通用应答
44 | else if (header.MessageId == JT808Constant.MSG_ID_TERMINAL_LOG_OUT)
45 | {
46 | logger.Info(">>>>>[终端注销],终端ID={0},流水号={1}", header.TerminalId, header.MessageSerial);
47 |
48 | }//5.位置信息汇报 ==> 平台通用应答
49 | else if (header.MessageId == JT808Constant.MSG_ID_TERMINAL_LOCATION_INFO_UPLOAD)
50 | {
51 | ProcessLocationInfo(req);
52 | logger.Info(">>>>>[位置信息汇报],终端ID={0},流水号={1}", header.TerminalId, header.MessageSerial);
53 |
54 | }// 其他情况
55 | else
56 | {
57 | logger.Info(">>>>>[其他情况],终端ID={0},流水号={1},消息ID={2}", header.TerminalId, header.MessageSerial, header.MessageId);
58 |
59 | }
60 | }
61 |
62 | #region 协议解析
63 |
64 | ///
65 | /// 终端注册
66 | ///
67 | ///
68 | private void ProcessTerminalRegist(JT808Message req)
69 | {
70 | try
71 | {
72 | #region 终端注册解析
73 | byte[] data = req.MsgBody;
74 | ByteBuffer buf = ByteBuffer.Wrap(data);
75 | TerminalRegInfo reginfo = new TerminalRegInfo();
76 | // 1. byte[0-1] 省域ID(WORD)
77 | reginfo.ProvinceId = buf.GetShort();
78 |
79 | // 2. byte[2-3] 设备安装车辆所在的市域或县域,市县域ID采用GB/T2260中规定的行 政区划代码6位中后四位
80 | reginfo.CityId = buf.GetShort();
81 |
82 | // 3. byte[4-8] 制造商ID(BYTE[5]) 5 个字节,终端制造商编码
83 | byte[] ProductByte = new byte[5];
84 | for (int i = 0; i < ProductByte.Length; i++)
85 | {
86 | ProductByte[i] = buf.Get();
87 | }
88 | reginfo.ManufacturerId = DataUtil.ByteArrToString(ProductByte);
89 |
90 |
91 | // 4. byte[9-16] 终端型号(BYTE[8]) 八个字节, 此终端型号 由制造商自行定义 位数不足八位的,补空格
92 | byte[] ProductTypeByte = new byte[8];
93 | for (int i = 0; i < ProductTypeByte.Length; i++)
94 | {
95 | ProductTypeByte[i] = buf.Get();
96 | }
97 | reginfo.TerminalType = DataUtil.ByteArrToString(ProductTypeByte);
98 |
99 |
100 | // 5. byte[17-23] 终端ID(BYTE[7]) 七个字节, 由大写字母 和数字组成, 此终端 ID由制造 商自行定义
101 | byte[] TeridByte = new byte[7];
102 | for (int i = 0; i < TeridByte.Length; i++)
103 | {
104 | TeridByte[i] = buf.Get();
105 | }
106 | reginfo.TerminalId = DataUtil.ByteArrToString(TeridByte);
107 |
108 |
109 | // 6. byte[24] 车牌颜色(BYTE) 车牌颜 色按照JT/T415-2006 中5.4.12 的规定
110 | reginfo.LicensePlateColor = buf.Get();
111 |
112 | // 7. byte[25-x] 车牌(STRING) 公安交 通管理部门颁 发的机动车号牌
113 | byte[] LicenseByte = new byte[data.Length - 25];
114 | for (int i = 0; i < LicenseByte.Length; i++)
115 | {
116 | LicenseByte[i] = buf.Get();
117 | }
118 | reginfo.LicensePlate = DataUtil.ByteArrToString(LicenseByte);
119 | #endregion
120 | logger.Info("收到终端注册信息:{0}", JsonConvert.SerializeObject(reginfo));
121 | }
122 | catch (Exception ex)
123 | {
124 | logger.Error(ex, "终端注册0x0100解析异常:{0}", ex.Message);
125 | }
126 | ProcessRegistResponse(req);
127 |
128 | }
129 |
130 | private void ProcessLocationInfo(JT808Message req)
131 | {
132 | try
133 | {
134 | #region 位置数据解析
135 | byte[] bytes = req.MsgBody;
136 | ByteBuffer buf = ByteBuffer.Wrap(bytes);
137 |
138 | // 报警标识 byte[0-3]
139 | int alarm = buf.GetInt();
140 | AlarmInfo alarminfo = new AlarmInfo();
141 | alarminfo.OverSpeed = ((alarm >> 1) & 0x1) == 1;
142 | alarminfo.GnssFault = ((alarm >> 4) & 0x1) == 1;
143 | alarminfo.PowerLow = ((alarm >> 7) & 0x1) == 1;
144 | alarminfo.PowerOff = ((alarm >> 8) & 0x1) == 1;
145 |
146 | //byte[4-7] 状态(DWORD(32))
147 | int state = buf.GetInt();
148 | WorkStateInfo stateinfo = new WorkStateInfo();
149 | stateinfo.AccOn = (state & 0x1) == 1;//0:ACC 关;1: ACC 开
150 | stateinfo.Navigation = (state >> 1 & 0x1) == 1;// 0:未定位;1:定位
151 | stateinfo.Latitude_N_S = (state >> 2);
152 | stateinfo.Longitude_E_W = (state >> 3);
153 |
154 | LocationInfo locationInfo = new LocationInfo();
155 | locationInfo.AlarmState = alarminfo;
156 | locationInfo.StateInfo = stateinfo;
157 |
158 | // byte[8-11] 纬度(DWORD(32))
159 | //以度为单位的纬度值乘以 10 的 6 次方,精确到百万分之一度
160 | locationInfo.Lat = buf.GetInt() / 1000000.0;
161 |
162 | // byte[12-15] 经度(DWORD(32))
163 | //以度为单位的经度值乘以 10 的 6 次方,精确到百万分之一度
164 | locationInfo.Lon = buf.GetInt() / 1000000.0;
165 |
166 | //locationInfo.ShiftLat
167 | //locationInfo.ShiftLon
168 |
169 | //byte[16-17] 高程(WORD(16)) 海拔高度,单位为米( m)
170 | double altitude = buf.GetShort();
171 | locationInfo.Altitude = altitude;
172 |
173 | // byte[18-19] 速度(WORD) 1/10km/h
174 | double speed = buf.GetShort() / 10.0;
175 | locationInfo.Speed = speed;
176 |
177 | // byte[20-21] 方向(WORD) 0-359,正北为 0,顺时针
178 | int direction = buf.GetShort();
179 | locationInfo.Direction = direction;
180 |
181 | // byte[22-x] 时间(BCD[6]) YY-MM-DD-hh-mm-ss
182 | // GMT+8 时间,本标准中之后涉及的时间均采用此时区
183 | locationInfo.GpsTime = DataUtil.GetTimeFromBCD(buf.Get(), buf.Get(), buf.Get(), buf.Get(), buf.Get(), buf.Get());
184 | #endregion
185 | logger.Info("收到位置信息:{0}", JsonConvert.SerializeObject(locationInfo));
186 | }
187 | catch (Exception ex)
188 | {
189 | logger.Error(ex, "位置信息0x0200解析异常:{0}", ex.Message);
190 | }
191 | ProcessCommonResponse(req);
192 | }
193 | #endregion
194 |
195 | #region 应答相关
196 | ///
197 | /// 终端注册应答
198 | ///
199 | private void ProcessRegistResponse(JT808Message req)
200 | {
201 | try
202 | {
203 | #region 终端注册应答
204 | // Terminal register
205 | TerminalRegPlatformResp resp = new TerminalRegPlatformResp();
206 | // 手机号作为鉴权码
207 | resp.AuthCode = req.MsgHeader.TerminalId;
208 | // 应答流水号
209 | resp.ReplySerial = req.MsgHeader.MessageSerial;
210 | // 终端ID
211 | resp.TerminalId = req.MsgHeader.TerminalId;
212 | // 应答结果
213 | resp.ReplyCode = MessageResult.Success;
214 | DoResponse(req.channel, resp);
215 | #endregion
216 | }
217 | catch (Exception e)
218 | {
219 | logger.Error(e, "<<<<<[终端注册应答信息]处理错误>>>>>,{0}", e.Message);
220 | }
221 | }
222 | ///
223 | /// 平台通用应答
224 | ///
225 | ///
226 | private void ProcessCommonResponse(JT808Message req)
227 | {
228 | try
229 | {
230 | //logger.Debug("平台通用应答信息:{0}", JsonConvert.SerializeObject(req));
231 | JT808MessageHead reqHeader = req.MsgHeader;
232 | CommonPlatformResp respMsgBody = new CommonPlatformResp();
233 | CommonPlatformResp resp = new CommonPlatformResp();
234 | resp.TerminalId = req.MsgHeader.TerminalId;
235 | resp.ReplySerial = req.MsgHeader.MessageSerial;
236 | resp.ReplyId = req.MsgHeader.MessageId;
237 | resp.ReplyCode = MessageResult.Success;
238 | DoResponse(req.channel, resp);
239 | }
240 | catch (Exception e)
241 | {
242 | logger.Error(e, "<<<<<[平台通用应答信息]处理错误>>>>>,{0}", e.Message);
243 | }
244 | }
245 |
246 | ///
247 | /// 向客户端发送应答
248 | ///
249 | ///
250 | ///
251 | private void DoResponse(IChannelHandlerContext context, PlatformResp resp)
252 | {
253 | // 构建消息体属性对象
254 | JT808MessageBodyAttr attr = new JT808MessageBodyAttr();
255 | attr.EncryptionType = 0;
256 | byte[] body = resp.Encode();
257 | attr.MsgBodyLength = body.Length;
258 | attr.IsSplit = false;
259 |
260 | JT808MessageHead head = new JT808MessageHead();
261 | head.MessageId = resp.GetMessageId();
262 | head.MessageSerial = GetFlowId(context.Channel);
263 | head.TerminalId = resp.TerminalId;
264 | head.MsgBodyAttr = attr;
265 |
266 | // 构建JT/T808协议消息对象
267 | JT808Message message = new JT808Message();
268 | message.MsgHeader = head;
269 | message.MsgBody = body;
270 |
271 | byte[] reply = message.Encode();
272 | context.WriteAndFlushAsync(Unpooled.CopiedBuffer(reply));
273 |
274 |
275 | //ResponseData response = new ResponseData();
276 | //response.CmdID = message.MsgHeader.MessageId;
277 | //response.CmdSerialNo = message.MsgHeader.MessageSerial;
278 | //response.MsgBody = reply;
279 | //response.TerminalID = resp.TerminalId;
280 | //response.Time = response.GetTimeStamp();
281 | //context.WriteAndFlushAsync(response);
282 |
283 |
284 | }
285 | #endregion
286 | }
287 |
288 |
289 | }
290 |
--------------------------------------------------------------------------------
/DataGateway/GPS/JT808/Util/DataUtil.cs:
--------------------------------------------------------------------------------
1 | using DataGateway.GPS.JT808.Constant;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Globalization;
5 | using System.Text;
6 | using System.Text.RegularExpressions;
7 |
8 | namespace DataGateway.GPS.JT808.Util
9 | {
10 | public class DataUtil
11 | {
12 | ///
13 | /// 从BCD码转日期
14 | ///
15 | ///
16 | ///
17 | ///
18 | ///
19 | ///
20 | ///
21 | ///
22 | public static string GetTimeFromBCD(byte bcdYear, byte bcdMonth, byte bcdDay, byte bcdHour, byte bcdMinute,byte bcdSecond)
23 | {
24 | int year = 2000 + Bcd2decimal(bcdYear);
25 | int month = Bcd2decimal(bcdMonth);
26 | int day = Bcd2decimal(bcdDay);
27 | int hour = Bcd2decimal(bcdHour);
28 | int minute = Bcd2decimal(bcdMinute);
29 | int second = Bcd2decimal(bcdSecond);
30 |
31 | string dateString = string.Format("{0}-{1}-{2} {3}:{4}:{5}", year,month,day,hour,minute,second);
32 | //DateTime dt = DateTime.ParseExact(dateString, "yyyy-MM-dd hh:mm:ss", System.Globalization.CultureInfo.CurrentCulture);
33 | return dateString;
34 | }
35 |
36 |
37 | ///
38 | /// convert bcd to decimal
39 | ///
40 | ///
41 | ///
42 | public static int Bcd2decimal(byte b)
43 | {
44 | return (b >> 4 & 0x0F) * 10 + (b & 0x0F);
45 | }
46 |
47 | public static string ByteArrToString(byte[] ByteArr) {
48 | if (ByteArr == null || ByteArr.Length < 1)
49 | return "";
50 |
51 | return JT808Constant.STRING_ENCODING.GetString(ByteArr);
52 | }
53 |
54 | //static Regex reUnicode = new Regex(@"\\u([0-9a-fA-F]{4})", RegexOptions.Compiled);
55 |
56 | //public static string Decode(string s)
57 | //{
58 | // return reUnicode.Replace(s, m =>
59 | // {
60 | // short c;
61 | // if (short.TryParse(m.Groups[1].Value, System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture, out c))
62 | // {
63 | // return "" + (char)c;
64 | // }
65 | // return m.Value;
66 | // });
67 | //}
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/DataGateway/GPS/Server/DataServer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using DotNetty.Common.Internal.Logging;
4 | using DotNetty.Handlers.Logging;
5 | using DotNetty.Transport.Bootstrapping;
6 | using DotNetty.Transport.Channels;
7 | using DotNetty.Transport.Channels.Sockets;
8 | using Microsoft.Extensions.Logging.Console;
9 |
10 | namespace DataGateway.gps.server
11 | {
12 | public class DataServer
13 | {
14 | private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
15 |
16 | ///
17 | /// 引导辅助程序
18 | ///
19 | private readonly ServerBootstrap _bootstrap;
20 |
21 | ///
22 | /// 主工作线程组
23 | ///
24 | private readonly MultithreadEventLoopGroup _bossEventLoopGroup;
25 |
26 | ///
27 | /// 工作线程组
28 | ///
29 | private readonly MultithreadEventLoopGroup _workerEventLoopGroup;
30 |
31 | private IChannel _channel;
32 |
33 | ///
34 | /// 当服务器请求处理线程全满时,用于临时存放已完成三次握手的请求的队列的最大长度
35 | ///
36 | private int Backlog = 128;
37 |
38 | ///
39 | /// 服务端口
40 | ///
41 | private int Port;
42 |
43 |
44 | public DataServer(int port)
45 | {
46 | this.Port = port;
47 | _bootstrap = new ServerBootstrap();
48 | //主工作线程组,设置为1个线程
49 | _bossEventLoopGroup = new MultithreadEventLoopGroup(1);
50 | //工作线程组,默认为内核数*2的线程数
51 | _workerEventLoopGroup = new MultithreadEventLoopGroup();
52 | }
53 |
54 | public DataServer(int port, int backlog)
55 | {
56 | Port = port;
57 | Backlog = backlog;
58 | _bootstrap = new ServerBootstrap();
59 | //主工作线程组,设置为1个线程
60 | _bossEventLoopGroup = new MultithreadEventLoopGroup(1);
61 | //工作线程组,默认为内核数*2的线程数
62 | _workerEventLoopGroup = new MultithreadEventLoopGroup();
63 | }
64 |
65 | public async Task StartAsync()
66 | {
67 | try
68 | {
69 | logger.Info("服务器启动");
70 | Init();
71 | _channel = await _bootstrap.BindAsync(Port);
72 | logger.Info("开始监听端口:" + this.Port);
73 | }
74 | catch (Exception ex)
75 | {
76 | logger.Error("服务器初始化发生异常:" + ex.Message);
77 | }
78 | }
79 |
80 | public async Task StopAsync()
81 | {
82 | if (_channel != null) await _channel.CloseAsync();
83 | if (_bossEventLoopGroup != null && _workerEventLoopGroup != null)
84 | {
85 | await _bossEventLoopGroup.ShutdownGracefullyAsync();
86 | await _workerEventLoopGroup.ShutdownGracefullyAsync();
87 | }
88 | }
89 |
90 | protected void Init()
91 | {
92 | InternalLoggerFactory.DefaultFactory.AddProvider(
93 | new ConsoleLoggerProvider(
94 | (text, level) => level >= Microsoft.Extensions.Logging.LogLevel.Warning, true)
95 | );
96 |
97 | _bootstrap.Group(_bossEventLoopGroup, _workerEventLoopGroup);// 设置主和工作线程组
98 | _bootstrap.Channel();// 设置通道模式为TcpSocket
99 |
100 | //当服务器请求处理线程全满时,用于临时存放已完成三次握手的请求的队列的最大长度
101 | _bootstrap.Option(ChannelOption.SoBacklog, Backlog);//ChannelOption.SO_BACKLOG, 1024
102 | _bootstrap.Handler(new LoggingHandler(LogLevel.WARN));
103 |
104 | //_bootstrap.ChildHandler(new InboundSessionInitializer(inboundSession));
105 | //_bootstrap.ChildOption(ChannelOption.SoLinger,0);//Socket关闭时的延迟时间(秒)
106 |
107 | //注册
108 | _bootstrap.ChildHandler(new DataServerInitializer());
109 |
110 | _bootstrap.ChildOption(ChannelOption.SoKeepalive, true);//是否启用心跳保活机制
111 |
112 | //_bootstrap.ChildOption(ChannelOption.TcpNodelay,true);//启用/禁用Nagle算法
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/DataGateway/GPS/Server/DataServerInitializer.cs:
--------------------------------------------------------------------------------
1 | using DotNetty.Codecs;
2 | using DotNetty.Handlers.Logging;
3 | using DotNetty.Transport.Channels;
4 | using DotNetty.Transport.Channels.Sockets;
5 | using DataGateway.GPS.JT808.Handler;
6 |
7 | namespace DataGateway.gps.server
8 | {
9 | public class DataServerInitializer : ChannelInitializer
10 | {
11 | protected override void InitChannel(ISocketChannel channel)
12 | {
13 | var pipeline = channel.Pipeline;
14 |
15 |
16 | pipeline.AddLast("DebugLogging",
17 | new LoggingHandler(LogLevel.INFO));
18 |
19 | pipeline.AddLast("inhandler", new JT808ProInHandler());
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DataGateway/JT808DataServer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/DataGateway/Program.cs:
--------------------------------------------------------------------------------
1 | using DataGateway.gps.server;
2 | using DataGateway.GPS.JT808.Util;
3 | using DotNetty.Common.Internal.Logging;
4 | using DotNetty.Handlers.Logging;
5 | using DotNetty.Transport.Bootstrapping;
6 | using DotNetty.Transport.Channels;
7 | using DotNetty.Transport.Channels.Sockets;
8 | using Microsoft.Extensions.Logging.Console;
9 | using System;
10 | using System.Collections.Concurrent;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 | namespace DataGateway
15 | {
16 | class Program
17 | {
18 | private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
19 |
20 | static void Main(string[] args)
21 | {
22 | Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
23 |
24 | //注册GBK编码后面的解析 Btye[] 转String需要用到
25 | //Console.WriteLine(Encoding.GetEncoding("GBK"));
26 | DataServer jt808server = new DataServer(9623);
27 | jt808server.StartAsync().Wait();
28 |
29 | Console.ReadLine();
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/DataGateway/obj/DataGateway.csproj.nuget.cache:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "dgSpecHash": "nriFfJqH4EvVhl5R5QcTp+1dRAqd4yKDigHWS4y31ZOCTrv79lTjtgSixEbHUVZ6dg+k+NROXfvImRkuh4XgSg==",
4 | "success": true
5 | }
--------------------------------------------------------------------------------
/DataGateway/obj/DataGateway.csproj.nuget.g.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | True
5 | NuGet
6 | F:\CoreProject\JT808DataServer\DataGateway\obj\project.assets.json
7 | $(UserProfile)\.nuget\packages\
8 | C:\Users\Administrator\.nuget\packages\;C:\Program Files\dotnet\sdk\NuGetFallbackFolder
9 | PackageReference
10 | 4.4.0
11 |
12 |
13 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
14 |
15 |
16 |
17 | NLog.Config
18 | 4.5.3
19 | None
20 | PreserveNewest
21 | NLog.config
22 | True
23 | NLog.config
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/DataGateway/obj/DataGateway.csproj.nuget.g.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/DataGateway/obj/Debug/netcoreapp2.0/DataGateway.AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本:4.0.30319.42000
5 | //
6 | // 对此文件的更改可能会导致不正确的行为,并且如果
7 | // 重新生成代码,这些更改将会丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | using System;
12 | using System.Reflection;
13 |
14 | [assembly: System.Reflection.AssemblyCompanyAttribute("DataGateway")]
15 | [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
16 | [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
17 | [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
18 | [assembly: System.Reflection.AssemblyProductAttribute("DataGateway")]
19 | [assembly: System.Reflection.AssemblyTitleAttribute("DataGateway")]
20 | [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
21 |
22 | // 由 MSBuild WriteCodeFragment 类生成。
23 |
24 |
--------------------------------------------------------------------------------
/DataGateway/obj/Debug/netcoreapp2.0/DataGateway.AssemblyInfoInputs.cache:
--------------------------------------------------------------------------------
1 | 2fd5d36e5317db59227b7b5cf306301d25a019ce
2 |
--------------------------------------------------------------------------------
/DataGateway/obj/Debug/netcoreapp2.0/DataGateway.csproj.CopyComplete:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mingyunet/JT808-Server/7d35386fdd650cfd5bf0ff9075c441bab6cfb224/DataGateway/obj/Debug/netcoreapp2.0/DataGateway.csproj.CopyComplete
--------------------------------------------------------------------------------
/DataGateway/obj/Debug/netcoreapp2.0/DataGateway.csproj.CoreCompileInputs.cache:
--------------------------------------------------------------------------------
1 | 7dcccfe9ffde6afb09acc55d8f3e4e52036933b5
2 |
--------------------------------------------------------------------------------
/DataGateway/obj/Debug/netcoreapp2.0/DataGateway.csproj.FileListAbsolute.txt:
--------------------------------------------------------------------------------
1 | F:\CoreProject\MFrameDataServer\DataGateway\bin\Debug\netcoreapp2.0\DataGateway.deps.json
2 | F:\CoreProject\MFrameDataServer\DataGateway\bin\Debug\netcoreapp2.0\DataGateway.runtimeconfig.json
3 | F:\CoreProject\MFrameDataServer\DataGateway\bin\Debug\netcoreapp2.0\DataGateway.runtimeconfig.dev.json
4 | F:\CoreProject\MFrameDataServer\DataGateway\bin\Debug\netcoreapp2.0\DataGateway.dll
5 | F:\CoreProject\MFrameDataServer\DataGateway\obj\Debug\netcoreapp2.0\DataGateway.csprojResolveAssemblyReference.cache
6 | F:\CoreProject\MFrameDataServer\DataGateway\obj\Debug\netcoreapp2.0\DataGateway.csproj.CoreCompileInputs.cache
7 | F:\CoreProject\MFrameDataServer\DataGateway\obj\Debug\netcoreapp2.0\DataGateway.AssemblyInfoInputs.cache
8 | F:\CoreProject\MFrameDataServer\DataGateway\obj\Debug\netcoreapp2.0\DataGateway.AssemblyInfo.cs
9 | F:\CoreProject\MFrameDataServer\DataGateway\bin\Debug\netcoreapp2.0\NLog.config
10 | F:\CoreProject\MFrameDataServer\DataGateway\bin\Debug\netcoreapp2.0\DataGateway.pdb
11 | F:\CoreProject\MFrameDataServer\DataGateway\obj\Debug\netcoreapp2.0\DataGateway.dll
12 | F:\CoreProject\MFrameDataServer\DataGateway\obj\Debug\netcoreapp2.0\DataGateway.pdb
13 | F:\CoreProject\MFrameDataServer\DataGateway\bin\Debug\netcoreapp2.0\MingYu.NetWork.dll
14 | F:\CoreProject\MFrameDataServer\DataGateway\bin\Debug\netcoreapp2.0\MingYu.NetWork.pdb
15 |
--------------------------------------------------------------------------------
/DataGateway/obj/Debug/netcoreapp2.0/DataGateway.csprojResolveAssemblyReference.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mingyunet/JT808-Server/7d35386fdd650cfd5bf0ff9075c441bab6cfb224/DataGateway/obj/Debug/netcoreapp2.0/DataGateway.csprojResolveAssemblyReference.cache
--------------------------------------------------------------------------------
/DataGateway/obj/Debug/netcoreapp2.0/DataGateway.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mingyunet/JT808-Server/7d35386fdd650cfd5bf0ff9075c441bab6cfb224/DataGateway/obj/Debug/netcoreapp2.0/DataGateway.dll
--------------------------------------------------------------------------------
/DataGateway/obj/Debug/netcoreapp2.0/DataGateway.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mingyunet/JT808-Server/7d35386fdd650cfd5bf0ff9075c441bab6cfb224/DataGateway/obj/Debug/netcoreapp2.0/DataGateway.pdb
--------------------------------------------------------------------------------
/DataGateway/obj/Debug/netcoreapp2.0/JT808DataServer.AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本:4.0.30319.42000
5 | //
6 | // 对此文件的更改可能会导致不正确的行为,并且如果
7 | // 重新生成代码,这些更改将会丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | using System;
12 | using System.Reflection;
13 |
14 | [assembly: System.Reflection.AssemblyCompanyAttribute("JT808DataServer")]
15 | [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
16 | [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
17 | [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
18 | [assembly: System.Reflection.AssemblyProductAttribute("JT808DataServer")]
19 | [assembly: System.Reflection.AssemblyTitleAttribute("JT808DataServer")]
20 | [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
21 |
22 | // 由 MSBuild WriteCodeFragment 类生成。
23 |
24 |
--------------------------------------------------------------------------------
/DataGateway/obj/Debug/netcoreapp2.0/JT808DataServer.AssemblyInfoInputs.cache:
--------------------------------------------------------------------------------
1 | c1d67bc181380273a01cff286a18312e967e5725
2 |
--------------------------------------------------------------------------------
/DataGateway/obj/Debug/netcoreapp2.0/JT808DataServer.csproj.CopyComplete:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mingyunet/JT808-Server/7d35386fdd650cfd5bf0ff9075c441bab6cfb224/DataGateway/obj/Debug/netcoreapp2.0/JT808DataServer.csproj.CopyComplete
--------------------------------------------------------------------------------
/DataGateway/obj/Debug/netcoreapp2.0/JT808DataServer.csproj.CoreCompileInputs.cache:
--------------------------------------------------------------------------------
1 | 3df02ae413fa5cdb043cf5e3db949a5b5607656c
2 |
--------------------------------------------------------------------------------
/DataGateway/obj/Debug/netcoreapp2.0/JT808DataServer.csproj.FileListAbsolute.txt:
--------------------------------------------------------------------------------
1 | F:\CoreProject\JT808DataServer\DataGateway\bin\Debug\netcoreapp2.0\NLog.config
2 | F:\CoreProject\JT808DataServer\DataGateway\bin\Debug\netcoreapp2.0\JT808DataServer.deps.json
3 | F:\CoreProject\JT808DataServer\DataGateway\bin\Debug\netcoreapp2.0\JT808DataServer.runtimeconfig.json
4 | F:\CoreProject\JT808DataServer\DataGateway\bin\Debug\netcoreapp2.0\JT808DataServer.runtimeconfig.dev.json
5 | F:\CoreProject\JT808DataServer\DataGateway\bin\Debug\netcoreapp2.0\JT808DataServer.dll
6 | F:\CoreProject\JT808DataServer\DataGateway\bin\Debug\netcoreapp2.0\JT808DataServer.pdb
7 | F:\CoreProject\JT808DataServer\DataGateway\obj\Debug\netcoreapp2.0\JT808DataServer.csproj.CoreCompileInputs.cache
8 | F:\CoreProject\JT808DataServer\DataGateway\obj\Debug\netcoreapp2.0\JT808DataServer.AssemblyInfoInputs.cache
9 | F:\CoreProject\JT808DataServer\DataGateway\obj\Debug\netcoreapp2.0\JT808DataServer.AssemblyInfo.cs
10 | F:\CoreProject\JT808DataServer\DataGateway\obj\Debug\netcoreapp2.0\JT808DataServer.dll
11 | F:\CoreProject\JT808DataServer\DataGateway\obj\Debug\netcoreapp2.0\JT808DataServer.pdb
12 | F:\CoreProject\JT808DataServer\DataGateway\obj\Debug\netcoreapp2.0\JT808DataServer.csprojResolveAssemblyReference.cache
13 | D:\My Project\github\JT808-Server\DataGateway\obj\Debug\netcoreapp2.0\JT808DataServer.csproj.CoreCompileInputs.cache
14 | D:\My Project\github\JT808-Server\DataGateway\obj\Debug\netcoreapp2.0\JT808DataServer.AssemblyInfoInputs.cache
15 | D:\My Project\github\JT808-Server\DataGateway\obj\Debug\netcoreapp2.0\JT808DataServer.AssemblyInfo.cs
16 | D:\My Project\github\JT808-Server\DataGateway\obj\Debug\netcoreapp2.0\JT808DataServer.dll
17 | D:\My Project\github\JT808-Server\DataGateway\obj\Debug\netcoreapp2.0\JT808DataServer.pdb
18 | D:\My Project\github\JT808-Server\DataGateway\bin\Debug\netcoreapp2.0\NLog.config
19 | D:\My Project\github\JT808-Server\DataGateway\bin\Debug\netcoreapp2.0\JT808DataServer.deps.json
20 | D:\My Project\github\JT808-Server\DataGateway\bin\Debug\netcoreapp2.0\JT808DataServer.runtimeconfig.json
21 | D:\My Project\github\JT808-Server\DataGateway\bin\Debug\netcoreapp2.0\JT808DataServer.runtimeconfig.dev.json
22 | D:\My Project\github\JT808-Server\DataGateway\bin\Debug\netcoreapp2.0\JT808DataServer.dll
23 | D:\My Project\github\JT808-Server\DataGateway\bin\Debug\netcoreapp2.0\JT808DataServer.pdb
24 |
--------------------------------------------------------------------------------
/DataGateway/obj/Debug/netcoreapp2.0/JT808DataServer.csprojResolveAssemblyReference.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mingyunet/JT808-Server/7d35386fdd650cfd5bf0ff9075c441bab6cfb224/DataGateway/obj/Debug/netcoreapp2.0/JT808DataServer.csprojResolveAssemblyReference.cache
--------------------------------------------------------------------------------
/DataGateway/obj/Debug/netcoreapp2.0/JT808DataServer.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mingyunet/JT808-Server/7d35386fdd650cfd5bf0ff9075c441bab6cfb224/DataGateway/obj/Debug/netcoreapp2.0/JT808DataServer.dll
--------------------------------------------------------------------------------
/DataGateway/obj/Debug/netcoreapp2.0/JT808DataServer.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mingyunet/JT808-Server/7d35386fdd650cfd5bf0ff9075c441bab6cfb224/DataGateway/obj/Debug/netcoreapp2.0/JT808DataServer.pdb
--------------------------------------------------------------------------------
/DataGateway/obj/JT808DataServer.csproj.nuget.cache:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "dgSpecHash": "BF5elnishJvSQJmjfNaZvSKFi9hKYkZmzG3rf7DfVjaTCVrFmu0BtS1G4yRX6Joe8VGKgLATPhaWaXJFh8zS0A==",
4 | "success": true
5 | }
--------------------------------------------------------------------------------
/DataGateway/obj/JT808DataServer.csproj.nuget.g.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | True
5 | NuGet
6 | $(MSBuildThisFileDirectory)project.assets.json
7 | $(UserProfile)\.nuget\packages\
8 | C:\Users\TZ0528\.nuget\packages\;C:\Program Files\dotnet\sdk\NuGetFallbackFolder
9 | PackageReference
10 | 5.1.0
11 |
12 |
13 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
14 |
15 |
16 |
17 | NLog.Config
18 | 4.5.3
19 | None
20 | PreserveNewest
21 | NLog.config
22 | True
23 | NLog.config
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/DataGateway/obj/JT808DataServer.csproj.nuget.g.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/JT808-2013.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mingyunet/JT808-Server/7d35386fdd650cfd5bf0ff9075c441bab6cfb224/JT808-2013.pdf
--------------------------------------------------------------------------------
/JT808DataServer.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27004.2002
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808DataServer", "DataGateway\JT808DataServer.csproj", "{1F331AE8-2BF3-4F80-B226-3268C9817F3A}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {1F331AE8-2BF3-4F80-B226-3268C9817F3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {1F331AE8-2BF3-4F80-B226-3268C9817F3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {1F331AE8-2BF3-4F80-B226-3268C9817F3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {1F331AE8-2BF3-4F80-B226-3268C9817F3A}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {65728E46-F6F1-4DD8-85FC-2B88B6F7A319}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # .net core dotnetty tcp server (jt808)
2 |
3 | 在网上看到Azure团队开源的DotNetty框架,一时兴起写了个基于DotNetty的Tcp Server Demo
4 | 解析了JT808的部分指令,应答部分暂时未弄完(最近补全了应答部分,没做测试),代码写的比较随意请不要在意。
5 |
6 | 部分代码参考了java版本的jt808协议解析 https://github.com/hylexus/jt-808-protocol
7 |
8 | 感慨JAVA强大的同时,还是喜欢C#强大的语法,希望.net core发展越来越好
9 |
10 | 直接运行程序,端口默认9623(在Main方法里面修改),可以使用网络调试助手联调(Tool\NetAssist.exe)
11 |
12 | 
13 |
14 |
15 | # 部分JT808测试数据如下:
16 |
17 | ## 终端注册
18 | 7E0100002c0200000000150025002c0133373039363054372d54383038000000000000000000000000003033323931373001d4c142383838387b7E
19 |
20 | ## 终端鉴权
21 | 7E0102000B018170223038009D3138313730323233303338787E
22 |
23 | ## 轨迹数据
24 | 7E0200007D020181702230330003000000000000000101EA3B5906AFC37000000000000018050921435330011F310100D004000A0000D40164E10201A4E221545A43532D312E31332E3130392E342031372D31322D32382C4D5430335F503130E30F343630303031383633353537393237E41301CC0000708177443E7081C1A43D7081774535E504012C02580E7E
25 |
26 | ## 终端心跳
27 | 7E0002000001817022303801B8617E
28 |
--------------------------------------------------------------------------------
/Tool/NetAssist.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mingyunet/JT808-Server/7d35386fdd650cfd5bf0ff9075c441bab6cfb224/Tool/NetAssist.exe
--------------------------------------------------------------------------------
/Tool/data.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mingyunet/JT808-Server/7d35386fdd650cfd5bf0ff9075c441bab6cfb224/Tool/data.png
--------------------------------------------------------------------------------