Delphi最簡化非同步選擇TCP伺服器

来源:http://www.cnblogs.com/kmhr/archive/2016/09/08/5851637.html
-Advertisement-
Play Games

網上Delphi的Socket伺服器優良代碼,實在少見,索性寫個簡化的非同步Socket伺服器,雖然代碼較少,但卻該有的都有了,使用的是非同步選擇WSAAsyncSelect,減少了編寫線程的繁瑣。可能會問,性能如何?當然使用窗體消息通知,占用的是主線程,偵聽、發送、多個客戶端的接收都一個線程,大量數據 ...


    網上Delphi的Socket伺服器優良代碼,實在少見,索性寫個簡化的非同步Socket伺服器,雖然代碼較少,但卻該有的都有了,使用的是非同步選擇WSAAsyncSelect,減少了編寫線程的繁瑣。可能會問,性能如何?當然使用窗體消息通知,占用的是主線程,偵聽、發送、多個客戶端的接收都一個線程,大量數據時,性能當然是差強人意的,編寫這個代碼目的也不在於此。但是在實際的項目中,大數據量的情況也不多,以下是代碼:(Delphi7編譯)

  1 {
  2    最簡化的消息非同步Socket 非同步選擇WSAAsyncSelect, 沒有64的限制
  3 }
  4 
  5 program SocketDemo;
  6 
  7 {$APPTYPE CONSOLE}
  8 
  9 uses Windows, WinSock;
 10 
 11 const
 12   ListenPort : Word  = 12345;
 13   BufferSize : DWORD = 1024;
 14 
 15 type
 16   TConn = ^TConnData;
 17   TConnData = record
 18     FSocket: TSocket;
 19     FAddrIn: TSockAddr;
 20     Buffer : PChar;
 21     BufLen : Integer;
 22   end;
 23 
 24 procedure DoSocketData(Conn: TConn);
 25 var S: string;
 26 begin
 27   Writeln(Conn.Buffer);
 28   //這裡插入業務處理代碼
 29   S:= 'Server echo';
 30   send(Conn.FSocket, PChar(S)^, Length(S), 0);
 31 end;
 32 
 33 
 34 
 35 //--------- 以下不要修改 -----------
 36 const
 37   wcName : PChar = 'THrWndClass';
 38   WM_SOCKET = {WM_USER}$0400 + 101;        // 自定義消息
 39 
 40 var
 41   AddrInLen: Integer = SizeOf(TSockAddr);
 42 
 43 var FConns: array of TConn;
 44 
 45 function GetFreeConn: Integer;
 46 var i: Integer;
 47 begin
 48   Result:= -1;
 49   for i:=0 to High(FConns) do
 50   if FConns[i]=nil then begin
 51     Result:= i; Break;
 52   end;
 53   if Result<0 then begin
 54     Result:= Length(FConns); SetLength(FConns, Result+1);
 55   end;
 56   FConns[Result]:= New(TConn);
 57   GetMem(FConns[Result].Buffer, BufferSize+1);
 58   FConns[Result].BufLen:= BufferSize;
 59 end;
 60 
 61 function GetCltConn(S: TSocket): Integer;
 62 var i: Integer;
 63 begin
 64   for i:=0 to High(FConns) do
 65   if Assigned(FConns[i]) and (FConns[i].FSocket=S) then begin
 66     Result:= i;  Break;
 67   end;
 68 end;
 69 
 70 procedure FreeConn(S: TSocket);
 71 var id: Integer;
 72 var Conn: TConn;
 73 begin
 74   id:= GetCltConn(S);
 75   Conn:= FConns[id];
 76   if not Assigned(Conn) then Exit;
 77   FreeMem(Conn.Buffer);
 78   CloseSocket(Conn.FSocket);
 79   Dispose(Conn);
 80   FConns[id]:= nil;
 81 end;
 82 
 83 function WndProc(wnd, msg, sock, wm: DWORD): Integer; stdcall;
 84 var id, AddrLen: Integer;
 85 begin
 86   Result:= DefWindowProc(wnd, msg, sock, wm);
 87   if (msg<>WM_SOCKET) or (wm=0) then Exit;
 88   case LoWord(wm) of
 89     FD_ACCEPT:
 90       begin
 91         id:= GetFreeConn;
 92         with FConns[id]^ do begin
 93           FSocket:= Accept(sock, @FAddrIn, @AddrInLen);
 94           WSAAsyncSelect(FSocket, wnd, WM_SOCKET, FD_READ or FD_CLOSE);
 95         end;
 96       end;
 97     FD_READ:
 98       begin
 99         id:= GetCltConn(sock);
100         with FConns[id]^ do begin
101           BufLen:= Recv(sock, Buffer^, BufferSize, 0);
102           if (BufLen<0) or (BufLen>Buflen) then FreeConn(sock) else
103           begin
104             Buffer[BufLen]:= #0;
105             try DoSocketData(FConns[id]) except end;
106           end;
107         end;
108       end;
109     FD_CLOSE: FreeConn(sock);
110   end;
111 end;
112 
113 function MakeWndHandle(WndProc: Pointer; wcName: PChar): HWND;
114 var wc: TWndClass;
115 begin
116   FillChar(wc, SizeOf(wc), 0);
117   wc.lpfnWndProc  := WndProc;
118   wc.hInstance    := HInstance;
119   wc.lpszClassName:= wcName;
120   Windows.RegisterClass(wc);
121   Result:= CreateWindow(wcName,'HrWnd',0,0,0,0,0,0,0,HInstance,nil);
122 end;
123 
124 function SrvListen(Port: Word): Boolean;
125 var Wnd: HWND; S: TSocket; Addr: TSockAddrIn; WSAData: TWSAData;
126 begin
127   WSAStartup($0202, WSAData);
128   Addr.sin_family      := AF_INET;
129   Addr.sin_port        := Swap(Port);
130   Addr.sin_addr.S_addr := 0;
131   S:= Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
132   Bind(S, Addr, AddrInLen);
133 
134   Wnd:= MakeWndHandle(@WndProc, wcName);
135   WSAAsyncSelect(S, Wnd, WM_SOCKET, FD_ACCEPT or FD_CLOSE);
136   //Writeln(SysErrorMessage(WSAGetLastError()), ' Wnd: ', Wnd);
137   Listen(S, 5);
138 end;
139 
140 procedure SysFina;
141 begin
142   Windows.UnregisterClass(wcName, HInstance);
143   WSACleanup;
144 end;
145 
146 procedure Stay;
147 var msg: TMsg;
148 begin
149   while GetMessage(msg, 0, 0, 0) do begin
150     TranslateMessage(msg);
151     DispatchMessage (msg);
152   end;
153   PostQuitMessage(0);
154 end;
155 
156 begin
157   //if InitProc <> nil then TProcedure(InitProc);
158   SrvListen(ListenPort);
159   Stay;
160   SysFina;
161   Halt(0);
162 end.

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Verilog HDL的語言的運算符的範圍很廣,按照其功能大概可以分為以下幾類: (1)算術運算符 +,-,*,/,% !~ * / % + - << >> < <= > >= == !== ! & ^ ^~ | && || ?: 最高優先順序別 ↓ ↓ ↓ ↓ 最低優先順序別 (2)賦值運算符 =,< ...
  • php添加數據到xml文件中 導讀:php添加數據到xml文件中 xml文件:stu.xml: 複製代碼代碼如下: <?xml version="1.0" encoding="utf-8" ?><AllData><xueshengmen><xuesheng> <name>張三</name> <yuw ...
  • 此bug項目中使用elasticSearch中出現的,原因是,nio事件選擇器,在特性內核下以及jdk6版本中,出現不hold線程,死迴圈獲取事件的bug,導致cup使用率過高; 此bug在官網已被修複:http://bugs.java.com/bugdatabase/view_bug.do?bug ...
  • 一、H5分類 網頁開發,移動開發,移動混合開發, 二、所用知識點: APICloud:APICloud是為了開發APP的,所以如果用H5開發的移動端,需要發送簡訊,獲取照相機等就要用APICloud的了。 aui框架:aui框架就是專門開發移動端的框架。 三、怎樣用H5開發移動端? 我建議如果用H5 ...
  • .NET Getting Started with ASP.NET Core and VS Code Coding Standard Best Practices In C# Wire – Writing one of the fastest .NET serializers Other How D... ...
  • Windows下Nginx配置SSL實現Https訪問(包含證書生成) 首先要說明為什麼要實現https? HTTP全名超文本傳輸協議,客戶端據此獲取伺服器上的超文本內容。超文本內容則以HTML為主,客戶端拿到HTML內容後可根據規範進行解析呈現。因此,HTTP主要負責的是“內容的請求和獲取”。問題 ...
  • 待會蘋果要開發佈會 我寫完這篇文章就準備去看發佈會了,因為我買了好幾包瓜子和啤酒。由於蘋果的保密做的越來越差勁,該曝光的信息差不多全部曝光了,我們這種熬夜看發佈會的只不過是讓這些信息更加真實,或者說是一種習慣了吧,因為每次蘋果和錘子的發佈會都必不可少的守著電腦看。 你要問我最期待什麼新產品?可能是新 ...
  • Django簡介:Django是一個開放源代碼的Web應用框架,由Python寫成。採用了MVC的框架模式,即模型M,視圖V和控制器C。不過在Django實際使用中,Django更關註的是模型(Model)、模板(Template)和視圖(Views),稱為 MTV模式。Django的主要目的是簡便 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...