高效能非同步Socket伺服器(UDP)
稍作修改
採用非同步模式設計的UDP伺服器,原始碼如下:
實際使用時需繼承抽象類UDPServer,並實現非同步處理資料的相關方案,示例如下:using System; using System.Net; using System.Net.Sockets; using System.Threading; using System.IO; namespace TestUDPServer { public abstract class UDPServer { // the port to listen on private int udpPort; // the UDP socket private Socket udpSocket; // the ReaderWriterLock is used solely for the purposes of shutdown (Stop()). // since there are potentially many "reader" threads in the internal .NET IOCP // thread pool, this is a cheaper synchronization primitive than using // a Mutex object. This allows many UDP socket "reads" concurrently - when // Stop() is called, it attempts to obtain a writer lock which will then // wait until all outstanding operations are completed before shutting down. // this avoids the problem of closing the socket with outstanding operations // and trying to catch the inevitable ObjectDisposedException. private ReaderWriterLock rwLock = new ReaderWriterLock(); // number of outstanding operations. This is a reference count // which we use to ensure that the threads exit cleanly. Note that // we need this because the threads will potentially still need to process // data even after the socket is closed. private int rwOperationCount = 0; // the all important shutdownFlag. This is synchronized through the ReaderWriterLock. private bool shutdownFlag = true; // these abstract methods must be implemented in a derived class to actually do // something with the packets that are sent and received. protected abstract void PacketReceived(UDPPacketBuffer buffer); protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent); // ServiceName String ServiceName = "test"; public UDPServer(int port) { this.udpPort = port; } public void Start() { if (shutdownFlag) { // create and bind the socket IPEndPoint ipep = new IPEndPoint(IPAddress.Any, udpPort); udpSocket = new Socket( AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); udpSocket.Bind(ipep); // we're not shutting down, we're starting up shutdownFlag = false; // kick off an async receive. The Start() method will return, the // actual receives will occur asynchronously and will be caught in // AsyncEndRecieve(). // I experimented with posting multiple AsyncBeginReceives() here in an attempt // to "queue up" reads, however I found that it negatively impacted performance. AsyncBeginReceive(); } } protected void Stop() { if (!shutdownFlag) { // wait indefinitely for a writer lock. Once this is called, the .NET runtime // will deny any more reader locks, in effect blocking all other send/receive // threads. Once we have the lock, we set shutdownFlag to inform the other // threads that the socket is closed. rwLock.AcquireWriterLock(-1); shutdownFlag = true; udpSocket.Close(); rwLock.ReleaseWriterLock(); // wait for any pending operations to complete on other // threads before exiting. while (rwOperationCount > 0) Thread.Sleep(1); } } public bool IsRunning { // self-explanitory get { return !shutdownFlag; } } private void AsyncBeginReceive() { // this method actually kicks off the async read on the socket. // we aquire a reader lock here to ensure that no other thread // is trying to set shutdownFlag and close the socket. rwLock.AcquireReaderLock(-1); if (!shutdownFlag) { // increment the count of pending operations Interlocked.Increment(ref rwOperationCount); // allocate a packet buffer UDPPacketBuffer buf = new UDPPacketBuffer(); try { // kick off an async read udpSocket.BeginReceiveFrom( buf.Data, 0, UDPPacketBuffer.BUFFER_SIZE, SocketFlags.None, ref buf.RemoteEndPoint, new AsyncCallback(AsyncEndReceive), buf); } catch (SocketException se) { // something bad happened System.Diagnostics.EventLog.WriteEntry(ServiceName, "A SocketException occurred in UDPServer.AsyncBeginReceive():\n\n" + se.Message, System.Diagnostics.EventLogEntryType.Error); // an error occurred, therefore the operation is void. Decrement the reference count. Interlocked.Decrement(ref rwOperationCount); } } // we're done with the socket for now, release the reader lock. rwLock.ReleaseReaderLock(); } private void AsyncEndReceive(IAsyncResult iar) { // Asynchronous receive operations will complete here through the call // to AsyncBeginReceive // aquire a reader lock rwLock.AcquireReaderLock(-1); if (!shutdownFlag) { // start another receive - this keeps the server going! AsyncBeginReceive(); // get the buffer that was created in AsyncBeginReceive // this is the received data UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; try { // get the length of data actually read from the socket, store it with the // buffer buffer.DataLength = udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); buffer.StrData = System.Text.Encoding.UTF8.GetString(buffer.Data, 0, buffer.DataLength); // WritetText(string.Format("終端 IP 埠:{0}<br>接收資料:{1}<br>接收時間:{2}", buffer.RemoteEndPoint.ToString(), buffer.StrData, DateTime.Now.ToString())); // Console.WriteLine(buffer.RemoteEndPoint.ToString()); Console.WriteLine(buffer.StrData); // this operation is now complete, decrement the reference count Interlocked.Decrement(ref rwOperationCount); // we're done with the socket, release the reader lock rwLock.ReleaseReaderLock(); // call the abstract method PacketReceived(), passing the buffer that // has just been filled from the socket read. PacketReceived(buffer); } catch (SocketException se) { // something bad happened System.Diagnostics.EventLog.WriteEntry(ServiceName, "A SocketException occurred in UDPServer.AsyncEndReceive():\n\n" + se.Message, System.Diagnostics.EventLogEntryType.Error); // an error occurred, therefore the operation is void. Decrement the reference count. Interlocked.Decrement(ref rwOperationCount); // we're done with the socket for now, release the reader lock. rwLock.ReleaseReaderLock(); } } else { // nothing bad happened, but we are done with the operation // decrement the reference count and release the reader lock Interlocked.Decrement(ref rwOperationCount); rwLock.ReleaseReaderLock(); } } public void AsyncBeginSend(UDPPacketBuffer buf) { // by now you should you get the idea - no further explanation necessary rwLock.AcquireReaderLock(-1); if (!shutdownFlag) { try { Interlocked.Increment(ref rwOperationCount); udpSocket.BeginSendTo( buf.Data, 0, buf.DataLength, SocketFlags.None, buf.RemoteEndPoint, new AsyncCallback(AsyncEndSend), buf); } catch (SocketException se) { System.Diagnostics.EventLog.WriteEntry(ServiceName, "A SocketException occurred in UDPServer.AsyncBeginSend():\n\n" + se.Message, System.Diagnostics.EventLogEntryType.Error); } } rwLock.ReleaseReaderLock(); } private void AsyncEndSend(IAsyncResult iar) { // by now you should you get the idea - no further explanation necessary rwLock.AcquireReaderLock(-1); if (!shutdownFlag) { UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; try { int bytesSent = udpSocket.EndSendTo(iar); // note that call to the abstract PacketSent() method - we are passing the number // of bytes sent in a separate parameter, since we can't use buffer.DataLength which // is the number of bytes to send (or bytes received depending upon whether this // buffer was part of a send or a receive). PacketSent(buffer, bytesSent); } catch (SocketException se) { System.Diagnostics.EventLog.WriteEntry(ServiceName, "A SocketException occurred in UDPServer.AsyncEndSend():\n\n" + se.Message, System.Diagnostics.EventLogEntryType.Error); } } Interlocked.Decrement(ref rwOperationCount); rwLock.ReleaseReaderLock(); } #region 寫日誌記錄 除錯 string file = string.Empty; private string CreateFile() { string path = System.Environment.CurrentDirectory; file = string.Format("{0}/Log-{1}.html", path, DateTime.Now.ToString("yyyy-MM-dd").Split(' ')[0]); FileInfo fInfo = new FileInfo(file); if (!fInfo.Exists) { //建立檔案 FileStream fs = fInfo.Create(); string temp = "<HR COLOR=red>"; byte[] data = System.Text.Encoding.Default.GetBytes(temp); fs.Write(data, 0, data.Length); fs.Flush(); fs.Close(); fs.Dispose(); } return file; } private void WritetText(string text) { CreateFile(); try { StreamWriter sw = new StreamWriter(file, true, System.Text.Encoding.Default);//File.AppendText(file); byte[] data = System.Text.Encoding.Default.GetBytes(text + " <HR Size=1><HR COLOR=red>"); sw.WriteLine(text + " <HR Size=1><HR COLOR=red>"); sw.Flush(); sw.Close(); } catch (Exception) { throw; } } #endregion } }
輔助類UDPPacketBuffer.csusing System; namespace TestUDPServer { public class TUdpServer : UDPServer { public TUdpServer(int port) : base(port) { Console.WriteLine("Server [email protected]" + port.ToString()); } protected override void PacketReceived(UDPPacketBuffer buffer) { AsyncBeginSend(buffer); } protected override void PacketSent(UDPPacketBuffer buffer, int bytesSent) { } } }
using System.Net; namespace TestUDPServer { // this class encapsulates a single packet that // is either sent or received by a UDP socket public class UDPPacketBuffer { // size of the buffer public const int BUFFER_SIZE = 4096; // the buffer itself public byte[] Data; // length of data to transmit public int DataLength; // the (IP)Endpoint of the remote host public EndPoint RemoteEndPoint; /// <summary> /// 顯示資料 /// </summary> private string strData; public string StrData { get { return strData; } set { strData = value; } } public UDPPacketBuffer() { this.Data = new byte[BUFFER_SIZE]; // this will be filled in by the call to udpSocket.BeginReceiveFrom RemoteEndPoint = (EndPoint)new IPEndPoint(IPAddress.Any, 0); } public UDPPacketBuffer(byte[] data, EndPoint remoteEndPoint) { this.Data = data; this.DataLength = data.Length; this.RemoteEndPoint = remoteEndPoint; } } }
相關推薦
高效能非同步Socket伺服器(UDP)
稍作修改 採用非同步模式設計的UDP伺服器,原始碼如下: using System; using System.Net; using System.Net.Sockets; using System.Threading; using System.IO; names
Java系列講座二:Socket網絡通信實現聊天軟件項目講解(UDP)
tcp 網絡通信 udp socket 上一篇我們講了通過TCP方式實現網絡通信軟件開發的原理,思路及實現,今天跟大家談談Socket通信中UDP方式通信的軟件開發步驟及主要代碼講解,UDP實現方式實現的通信軟件特點是不分客戶端與服務器端,一個程序既是客戶端與是服務器端,典型軟件是一些
unity3D-----------socket客戶端、伺服器(簡單)
利用socket簡單的實現,客戶端和伺服器之間的通訊。 客戶端: using UnityEngine; using System.Collections; using System.Text; using System.Net; using System.Net.Soc
Linux下網路socket程式設計——實現伺服器(select)與多個客戶端通訊
Linux下網路socket程式設計——實現伺服器(select)與多個客戶端通訊 置頂 2017年06月23日 14:44:37 閱讀數:3225 標籤: socket程式設計伺服器與多個客戶端通epoll多路複用C語言網路程式設計 更多
Socket程式設計(二)回射客戶/伺服器的實現
TCP客戶/伺服器模型,即C/S模型 可以將這個模型類比為打電話。 TCP伺服器通過socket()建立一個套接字,相當於安裝一臺話機;然後為安裝好的話機繫結bind()一個電話號碼;讓話機處於監聽的狀態listen();等待客戶端的連線accept(),也就是等待對方電話撥打過來,如果一直
Java Socket應用(五) 基於UDP的Socket通訊之客戶端
UDPClient.java package com.yijia; import java.io.IOException; import java.net.*; /** * 建立時間:2018/10/4 15:44 * 作者: * 郵箱:[email p
Python基於socket程式設計(UDP版聊天)
説明:多臺電腦連同一網路可通訊。 有介面版待更; 目錄 一、UDP聊天(無介面) 1. 架構 2. 程式碼 3. 測試 二、UDP聊天(可視介面)
C#.網路程式設計 Socket基礎(一)Socket TCP協議 實現端到端(伺服器與客戶端)簡單字串通訊
簡介: 本章節主要討論了Socket的入門知識,還未針對Socket的難點問題(比如TCP的無訊息邊界問題)展開討論,往後在其他章節中進行研究。 注意點: 伺服器(比如臺式電腦)的IP為1.1.1.2,那麼客戶端(其他裝置,比如手機,Ipad)連線的一定是
C#.網路程式設計 Socket基礎(三) 基於WinForm系統Socket TCP協議 實現端到端(伺服器與客戶端).txt.word.png等不同型別檔案傳輸
一、簡介: 前面的兩篇介紹了字串傳輸、圖片傳輸: 其實,本文針對Socket基礎(二)進一步完成,以便可以進行多種檔案傳輸。 二、基於不同的流(檔案流、記憶體流、網路等)讀寫。 1、圖片傳輸 方法一:(在客戶端用檔案流傳送(即將圖片寫到檔案流去,以便傳送),
C#.網路程式設計 Socket基礎(四) WPF系統Socket TCP協議 伺服器與客戶端 不同型別檔案傳輸,同時解決UI執行緒與工作執行緒的卡頓問題
一、簡介 雖然,本文的前面幾篇文章在WinForm中實現了Socket TCP協議 伺服器與客戶端 不同型別檔案傳輸,詳情見 但是,卻沒有在WPF中實現 Socket TCP協議 伺服器與客戶端 不同型別檔案傳輸。因此,本文將描述如何在WPF中實現該功能。
Java Socket程式設計(五) 簡單的WEB伺服器
簡單的WEB伺服器一個簡單的WEB伺服器將由列表9.2這樣構建.當然,還必須要對方法和迴應事件進行改進.簡單的伺服器不會分析和儲存請求頭.新的WEB伺服器將分析和儲存請求,為以後的處理作準備.為了達到這個目的,你必須有一個包含HTTP請求的類.HTTPrequest類列表9.5列出了一個完整的HTTPrequ
JAVA網路程式設計 ——基於TCP的Socket程式設計(1)——實現伺服器端與客戶端的實時對話
第一篇文章,我先介紹以及記錄一下我所學的知識點。(總結了一下視訊老師講的東西)一,HTTP與Socket1.HTTP:超文字傳輸協議特點:客戶端傳送的請求需要伺服器端每次來響應,在請求結束之後主動釋放連線,從建立連線到關閉連線稱為“一次連線”,所以HTTP是“短連線”。2.S
java網路程式設計:13、基於UDP的socket程式設計(三)實現相互發送接收訊息
宣告:本教程不收取任何費用,歡迎轉載,尊重作者勞動成果,不得用於商業用途,侵權必究!!! 文章目錄 一、前言 二、基於UDP伺服器端程式的編寫 三、基於UDP客戶端程式的編寫 四、測試列印 五、系列文章(java網路程式設計) 通過上兩篇文章:1、瞭解了基於UDP
java網路程式設計:12、基於UDP的socket程式設計(二)程式碼通訊-簡單例項
宣告:本教程不收取任何費用,歡迎轉載,尊重作者勞動成果,不得用於商業用途,侵權必究!!! 文章目錄 一、基於UDP伺服器端程式的編寫 二、基於UDP客戶端程式的編寫 三、系列文章(java網路程式設計) 通過上篇文章瞭解了基於UDP通訊的理論、基本步驟以及它跟TCP的區別
java網路程式設計:11、基於UDP的socket程式設計(一)理論、基本步驟
宣告:本教程不收取任何費用,歡迎轉載,尊重作者勞動成果,不得用於商業用途,侵權必究!!! 文章目錄 一、基於UDP的socket程式設計 二、基本步驟 三、系列文章(java網路程式設計) 一、基於UDP的socket程式設計 對於基於UDP通訊來說,通訊雙方不需要建
java網路程式設計:9、基於TCP的socket程式設計(二)伺服器端迴圈監聽接收多個客戶端_多執行緒伺服器程式
宣告:本教程不收取任何費用,歡迎轉載,尊重作者勞動成果,不得用於商業用途,侵權必究!!! 文章目錄 一、核心程式碼編寫 1、伺服器端程式的編寫 2、客戶端程式的編寫 3、測試列印輸出 二、系列文章(java網路程式設計) 上篇講了基於tcp的程式設計的一些基礎知識
C#高效能大容量SOCKET併發(六):超時Socket斷開(守護執行緒)和心跳包
守護執行緒 在服務端版Socket程式設計需要處理長時間沒有傳送資料的Socket,需要在超時多長時間後斷開連線,我們需要獨立一個執行緒(DaemonThread)來輪詢,在執行斷開時,需要把Socket物件鎖定,並呼叫CloseClientSocket來斷開連線,具體
Netty搭建Socket伺服器(第一天學習)
為什麼要學習netty 當你寫了一段時間的客戶端以後你會發現除非你想寫opengl或者提別的複雜的圖形演算法,否則你不得不承認你只會寫一些邏輯的顯示,至於那些現在流行的,高併發,大資料,人工智慧就會越來越遠,於是我準備學習高併發的相關知識,順便也可以總結一下以前學習的c
高效能MySQL.讀書筆記(一)優化伺服器設定
MySQL有大量可以修改的引數——但不應該隨便去修改。通常只需要把基本的配置項配置正確(大部分情況下只有很少一些引數是真正重要的),應該將更多的時間花在schema的優化、索引,以及查詢設計上。 確保基本的配置是正確的,如果碰到了問題,並且問題是由於伺服器的某部分導致的,而這恰好可以通過某個配置項解決,那麼需
C++伺服器(一):瞭解Linux下socket程式設計
最近想要用C++寫個socket的伺服器,用於日常的專案開發。 不過,我是新手,那就慢慢地學習一下吧。 Server #include<iostream> using namespace std; //head files of