GPS服務端(上)-Socket服務端(golang)

 從第一次寫GPS的服務端到如今,已通過去了八年時光。一直是用.net修修改改,從本身寫的socket服務,到suppersocket,都是勉強在堅持着,沒有真正的穩定過。前端

  最近一段時間,服務端又出了兩個問題:golang

  一、UDP服務:System.Net.Sockets.SocketException (0x80004005): 當該操做在進行中,因爲保持活動的操做檢測到一個故障,該鏈接中斷。數據庫

  二、數據庫操做:System.Data.SqlClient.SqlException (0x80131904): 事務(進程 ID 54)與另外一個進程被死鎖在 鎖 資源上,而且已被選做死鎖犧牲品。請從新運行該事務。服務器

  第一點估計真的是.net socket框架的問題,嘗試過網上搜索的解決方案都沒有解決,一樣的程序在另一臺服務器正常,惟獨其中一臺隔三差五的就出現這個問題 。如下是服務端部分代碼:session

 1      /// <summary>
 2         /// 初始化監聽
 3         /// </summary>
 4         private void InitServer()
 5         {
 6             server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
 7             uint IOC_IN = 0x80000000;
 8             uint IOC_VENDOR = 0x18000000;
 9             uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
10             server.IOControl((int)SIO_UDP_CONNRESET, new Byte[] { Convert.ToByte(false) }, null);//不知道這句有沒有用。
11             string hostName = Dns.GetHostName();   //獲取本機名
12             IPHostEntry localhost = Dns.GetHostEntry(hostName);
13             IPAddress[] ips = localhost.AddressList;
14             IPAddress localaddr = null;
15             foreach (IPAddress ip in ips)
16             {
17                 if (ip.IsIPv6LinkLocal || ip.IsIPv6Teredo)
18                 {
19                     continue;
20                 }
21                 localaddr = ip;
22             }
23 
24             state = new State(server);
25             server.Bind(new IPEndPoint(localaddr, _config.Port));
26             server.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.RemoteEP, new AsyncCallback(ReceiveCallBack), state);
27         }
 1   private void ReceiveCallBack(IAsyncResult ar)
 2         {
 3             try
 4             {
 5                 State _state = ar.AsyncState as State;
 6                 int size = server.EndReceiveFrom(ar, ref _state.RemoteEP);
 7                 if (size > 0)
 8                 {
 9                     byte[] data = new byte[size];
10                     Array.Copy(_state.Buffer, 0, data, 0, size);
11                     var session = AddClient(_state.RemoteEP, data);
12                     if (session != null)
13                     {
14                         _state.Session = session;
15                     }
16                     OnReceived?.Invoke(_state.Session, data);
17                     server.BeginReceiveFrom(_state.Buffer, 0, _state.Buffer.Length, 0, ref _state.RemoteEP, new AsyncCallback(ReceiveCallBack), _state);
18                 }
19                 else
20                 {
21                     LogHelper.Error("size<=0");
22                     _state = ar.AsyncState as State;
23                     server.BeginReceiveFrom(_state.Buffer, 0, _state.Buffer.Length, SocketFlags.None, ref _state.RemoteEP, new AsyncCallback(ReceiveCallBack), _state);
24                     //Dispose();
25                     //SessionClosed?.Invoke(_state.Session);
26                 }
27             }
28             catch (SocketException ex)
29             {
30                 LogHelper.Error(ex.ToString());//此處報錯
31                 try
32                 {
33                     Dispose();
34                     InitServer();
35                 }
36                 catch (Exception e)
37                 {
38                     LogHelper.Error($"重啓時報錯{e.ToString()}");
39                 }
41             }
42         }

  而第二點數據庫的操做,則是設計缺陷了,四個端口接收不一樣協議的終端數據,定時5秒批量寫入歷史數據表和批量update一張最新數據的表,這張最新數據表還有前端在定時select。架構

  時不時的深更半夜接到客戶電話要求處理,也是心累了,所以,想嘗試一下用golang+MQ+.net的解決方案,試圖完全解決以上煩惱。成功與否那是後話,先要有所嘗試嘛。框架

  架構圖:socket

 

  這種設計可能存在的風險:Socket Server寫入MQ Server的速度若是大於MQ Clients到SqlServer的速度,會致使數據延時,最主要服務器內存受不了。系統需求又不容許MQ消費者丟棄任何數據。工具

  不要緊,咱們先假設處理速度能快於接收速度,不然生活無法繼續,哈哈。ui

  先上一段golang服務端代碼

package main

import (
    "fmt"
    "net"
    "time"
    "configmanager"
    "logger"
)
func checkError(err error){
    if err != nil {
        fmt.Println(err)
    }
}
func clientHandle(conn *net.UDPConn) {
    var buf [512]byte
    size, addr, err := conn.ReadFromUDP(buf[0:])
    if err != nil {
        logger.Error.Println(err)
        return
    }
    
    daytime :=time.Now().Format("2006-01-02 15:04:05");
    var buff =buf[0:size]
    logger.Info.Printf("%x\r\n",buff)//此處先打印,下篇寫入MQ
    conn.WriteToUDP([]byte(daytime), addr)
}
func main(){
    configmanager.Initialize()//初始化配置文件處理包,將配置config.ini寫入到全局映射AppSettings中
    port := configmanager.AppSettings["port"]
    logger.Info.Print("開始在" + port + "監聽\r\n")
    udpaddr,err:=net.ResolveUDPAddr("udp4",":" + port)
    checkError(err)
    udpconn,err := net.ListenUDP("udp",udpaddr)
    checkError(err)
    for{
        clientHandle(udpconn);
    }
}

打開編譯後的應用程序,同時打開TcpUdp壓測工具

以上,golang的UDP服務端就成功了,下一篇再要看看golang是怎麼操做rabbitmq的

相關文章
相關標籤/搜索