本文主要講述:
1、正常通訊中握手建立
2、一對多的通訊
3、發送接收資料格式轉換
4、資源釋放
5、開啟並保持服務監聽
1、握手建立正常的通訊通道
項目需要通訊的雙方(假設是一個上位機、一個下位機)之間需要建立一個穩定的通道,以便進行通訊。本項目中具體操作是:上位機作為伺服器,下位機作為用戶端,同時制定通訊協定。上位機首先開啟監聽等待建立通道,下位機主動串連上位機後發送串連成功的資訊到上位機,上位機根據通訊協定發送資料到下位機,此時通道已經建立。但為了保險起見(同時遵循三向交握),用戶端再次發送資料到上位機告知通道建立完畢。
2、一對多通訊
項目需求是一個上位機多個下位機,這就確定了上位機做為伺服器端,下位機作為用戶端主動串連伺服器。一對一通訊時只有一個socket通道,因此無論是上位機還是下位機在發送和接收資料的時候都不會存在資料亂髮亂收的情況。一對多意味著上位機和下位機會建立起多個通道,因此在發送資料時需要記錄哪一個下位機處於哪個socket通道中,以便進行邏輯處理。本文處理一對多通訊的過程是:
1)首先建立一個對話類Session:
public class Session { public Socket ClientSocket { get; set; }//用戶端的socket public string IP;//用戶端的ip public Session(Socket clientSocket) { this.ClientSocket = clientSocket; this.IP = GetIPString(); } public string GetIPString() { string result = ((IPEndPoint)ClientSocket.RemoteEndPoint).Address.ToString(); return result; } }
2)在服務端socket監聽時:
IPEndPoint loaclEndPoint = new IPEndPoint(IPAddress.Any, Port); SocketLister = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); SocketLister.Bind(loaclEndPoint); try { SocketLister.Listen(MaxConnection); while (IsRunning) { ClientSocket = SocketLister.Accept(); //儲存socket Session newSession = new Session(ClientSocket); lock (sessionLock) { sessionTable.Add(newSession.IP, newSession); } SocketConnection socketConnection = new SocketConnection(ClientSocket); socketConnection.ReceiveDatagram();//接收資料 } } catch (SocketException ex) { }
//聲明
public Hashtable sessionTable = new Hashtable ();//包括用戶端工作階段
private object sessionLock = new object();
為了便於理解,把整個服務端socket的建立都寫在上面。
3)發送資料到不同的用戶端
Hashtable ht = serverSocket.sessionTable; foreach (Session session in ht.Values) { if (session.IP == "127.0.0.1")//example { SocketConnection socketConnection = new SocketConnection(session.ClientSocket); string str = "C300010002D2"; byte[] sendBytes = StrToHexByte(str); socketConnection.Send(sendBytes); } }
SocketConnection類已經被使用多次,寫在下面:
public class SocketConnection:IDisposable { public ServerSocket Server { get; set; } public Byte[] MsgBuffer = null; private int totalLength = 0; public int CurrentBufferLength; private Socket _ClientSocket = null; public Socket ClientSock { get{ return this._ClientSocket; } } public SocketConnectionType Type { get; private set; } #region Constructor public SocketConnection(ServerSocket server, Socket sock) { this.Server = server; this._ClientSocket = sock; this.Type = SocketConnectionType.Server; } public SocketConnection(Socket sock) { this._ClientSocket = sock; this.Type = SocketConnectionType.Client; } #endregion #region Events public SocketConnectionDelegate OnConnect = null;//是否串連 public SocketConnectionDelegate OnLostConnect = null;//中斷串連 public ReceiveDataDelegate OnReceiveData = null;//接收資料 #endregion #region Connect public void Connect(IPAddress ip, int port) { this.ClientSock.BeginConnect(ip, port, ConnectCallback, this.ClientSock); } private void ConnectCallback(IAsyncResult ar) { try { Socket handler = (Socket)ar.AsyncState; handler.EndConnect(ar); if (OnConnect != null) { OnConnect(this); } ReceiveDatagram(); } catch (SocketException ex) { } } #endregion #region Send public void Send(string data) { Send(System.Text.Encoding.UTF8.GetBytes(data)); } public void Send(byte[] byteData) { try { int length = byteData.Length; byte[] head = BitConverter.GetBytes(length); byte[] data = new byte[head.Length + byteData.Length]; Array.Copy(head, data, head.Length); Array.Copy(byteData, 0, data, head.Length, byteData.Length); this.ClientSock.BeginSend(data, 0, data.Length, 0, new AsyncCallback(SendCallback), this.ClientSock); } catch (SocketException ex) { } } private void SendCallback(IAsyncResult ar) { try { Socket handler = (Socket)ar.AsyncState; handler.EndSend(ar); } catch (SocketException ex) { } } #endregion #region ReceiveDatagram public void ReceiveDatagram() { SocketStateObject state = new SocketStateObject(); state.workSocket = _ClientSocket; _ClientSocket.BeginReceive(state.buffer, 0, SocketStateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); } private void ReceiveCallback(IAsyncResult ar) { SocketStateObject state = (SocketStateObject)ar.AsyncState; Socket handler = state.workSocket; if (handler.Connected) { try { state.bytesRead = handler.EndReceive(ar); if (state.bytesRead > 0) { OnDataRecivedCallback(state.buffer, state.bytesRead); Array.Clear(state.buffer, 0, state.buffer.Length); state.bytesRead = 0; handler.BeginReceive(state.buffer, 0, SocketStateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); } else { //