從第一次寫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的